当前位置: 首页 > article >正文

Android Hilt 教程

Android Hilt 教程 —— 一看就懂,一学就会

1. 什么是 Hilt?为什么要用 Hilt?

Hilt 是 Android 官方推荐的 依赖注入(DI)框架,基于 Dagger 开发,能够大大简化依赖注入的使用。

为什么要用 Hilt?

  • 简化依赖注入:不需要手写复杂的 Dagger 代码,Hilt 提供了简单易懂的注解。
  • 管理对象的生命周期:Hilt 会根据不同的组件(如 Activity、ViewModel、Application)自动管理依赖对象的创建和销毁。
  • 提高代码的模块化:通过 Hilt 提供的 @Module,可以让代码更加清晰,方便维护和测试。

2. Hilt 的基本使用步骤

步骤 1:添加 Hilt 依赖

build.gradle (Project) 中添加 Hilt 插件:

buildscript {ext.hilt_version = '2.28-alpha'dependencies {classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"}
}新android studio 版本:
plugins {id 'com.google.dagger.hilt.android' version '2.51.1' apply false
}

app/build.gradle 中:

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'android {...
}dependencies {implementation("com.google.dagger:hilt-android:2.51.1")kapt("com.google.dagger:hilt-android-compiler:2.51.1")
}

注意: Hilt 需要 kotlin-kapt 来处理注解。

步骤 2:在 Application 级别启用 Hilt

创建一个继承 Application 的类,并添加 @HiltAndroidApp 注解。

import android.app.Application
import dagger.hilt.android.HiltAndroidApp@HiltAndroidApp
class MyApplication : Application()

作用: 让 Hilt 进行全局依赖注入的初始化。

步骤 3:在 Activity 中使用 Hilt 进行依赖注入

MainActivity 中使用 @AndroidEntryPoint 让 Hilt 自动提供对象:

import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 直接注入对象private val viewModel: MainViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 显示直接注入的结果val result1 = someClass.doSomething()findViewById<TextView>(R.id.tvDirectResult).text = "Direct injection: $result1"// 观察 ViewModel 的结果viewModel.doWork { result ->findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"}}
}

步骤 4:在 ViewModel 中使用 Hilt 进行依赖注入

ViewModel 不能直接使用 @Inject,需要 @HiltViewModel 注解:

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject@HiltViewModel
class MainViewModel @Inject constructor(private val someClass: SomeClass,private val someOtherClass: SomeOtherClass
) : ViewModel() {fun doWork(callback: (String) -> Unit) {val result1 = someClass.doSomething()val result2 = someOtherClass.doSomething()callback("$result1, $result2")}
}

步骤 5:创建普通类并让 Hilt 提供实例

方法 1:直接使用 @Inject 注解(适用于简单对象)

如果是 没有构造参数 的类,可以直接用 @Inject 标注构造函数:


import javax.inject.Injectclass SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}

Hilt 会自动创建 SomeClass 的实例,并在需要的地方注入。

方法 2:使用 @Module 提供实例(适用于需要配置的对象)

如果类 不能直接使用 @Inject(例如:构造函数需要参数),需要在 @Module 里提供:

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideSomeOtherClass(): SomeOtherClass {return SomeOtherClass()}
}

然后创建 SomeOtherClass

class SomeOtherClass {fun doSomething() = "Hello from SomeOtherClass!"
}

3. Hilt 的生命周期管理

Hilt 提供不同作用域,决定对象的生命周期:

  • @Singleton —— 应用级,对象在整个应用生命周期内存在。
  • @ActivityScoped —— Activity 级,对象在同一个 Activity 内共享。
  • @ViewModelScoped —— ViewModel 级,对象绑定到 ViewModel 的生命周期。
  • @FragmentScoped —— Fragment 级,对象在同一个 Fragment 内共享。

例如,如果 SomeOtherClass 只在 Activity 级别存在:

@Module
@InstallIn(ActivityComponent::class)
object ActivityModule {@Provides@ActivityScopedfun provideSomeOtherClass(): SomeOtherClass {return SomeOtherClass()}
}

4. 总结:为什么选择 Hilt?

代码简洁:比 Dagger 需要更少的模板代码。
易学易用:通过注解即可完成依赖注入。
自动管理生命周期:减少手动管理实例的工作。
官方支持:推荐用于 Android 开发。

按照本教程,已经学会如何在 ActivityViewModel普通类 中使用 Hilt 进行依赖注入

二 @Inject 后面为什么需要加上constructor()

在 Kotlin 中,@Inject constructor() 主要用于 依赖注入,告诉 Hilt 如何创建 SomeClass 的实例。


1. 为什么 @Inject 需要加 constructor()

在 Kotlin 里,constructor()显式声明主构造函数 的方式,而 @Inject 只能标注 构造函数,不能直接标注类名。

例如:

class SomeClass @Inject constructor() { fun doSomething() = "Hello Hilt!"
}

这里 @Inject constructor() 表示:

  • Hilt 需要通过这个构造函数来创建 SomeClass 的实例
  • Hilt 发现 @Inject 后,会自动提供 SomeClass 的对象,无需手动创建。

2. 如果不加 constructor 会怎样?

如果尝试这样写:

class SomeClass @Inject {  // ❌ 语法错误fun doSomething() = "Hello Hilt!"
}

会直接 编译错误,因为 @Inject 必须作用于构造函数,而 constructor 是构造函数的 显式声明方式


3. constructor 省略的情况

当类没有显式的 constructor 关键字时,它默认是 无参构造函数

class SomeClass {fun doSomething() = "Hello!"
}

但如果要让 Hilt 注入实例,必须 显式@Inject constructor()


4. 带参数的情况

如果 SomeClass 依赖其他类,比如 AnotherClass,Hilt 也能自动提供:

class AnotherClass @Inject constructor()class SomeClass @Inject constructor(private val anotherClass: AnotherClass) {fun doSomething() = "Using ${anotherClass.toString()}"
}

Hilt 会先创建 AnotherClass,然后再创建 SomeClass 并把 AnotherClass 传进去。


总结

@Inject constructor() 是 Hilt 依赖注入的核心,告诉 Hilt 如何实例化一个类。
不能直接写 @Inject,必须加 constructor()
如果类有依赖,Hilt 会自动提供并注入参数

这样,Hilt 就能帮们自动管理 SomeClass 的创建,而不需要手动 new SomeClass() 了!

三 代码含义


1
// 观察 ViewModel 的结果
viewModel.doWork { result ->
findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"
}2 		
fun doWork(callback: (String) -> Unit) {
val result1 = someClass.doSomething()
val result2 = someOtherClass.doSomething()
callback("$result1, $result2")
} 

这段代码涉及 Lambda 回调 机制,它的作用是异步或延迟地获取 doWork 方法执行后的结果,并在外部(比如 UI 层)进行处理。

代码解析


1. 观察 ViewModel 的结果
viewModel.doWork { result ->findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"
}
  • 这里 viewModel.doWork 是一个方法,它接收一个 Lambda 回调,即 { result -> ... }
  • resultdoWork 方法执行完成后,回传的结果
  • findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result" 这行代码的意思是:当 doWork 任务完成后,将 result 赋值给 TextView,在 UI 界面显示出来。

2. doWork 方法定义
fun doWork(callback: (String) -> Unit) {val result1 = someClass.doSomething()val result2 = someOtherClass.doSomething()callback("$result1, $result2")
}
  • doWork 方法接收一个参数 callback,类型是 (String) -> Unit,即 一个以 String 为参数、无返回值的 Lambda 表达式
  • someClass.doSomething()someOtherClass.doSomething() 是执行的两个操作,它们可能返回字符串类型的结果。
  • callback("$result1, $result2")
    • 这个 callback 就是上面调用 doWork 时传入的 { result -> ... } Lambda。
    • "$result1, $result2" 生成一个字符串,格式类似 "value1, value2"
    • 这个字符串作为参数,传递给 callback,从而调用 { result -> ... } 代码块,并将 "$result1, $result2" 赋值给 result

result 是什么?

  • resultdoWork 任务执行后,回传给 Lambda 代码块的结果
  • 具体值取决于 someClass.doSomething()someOtherClass.doSomething() 的返回值。

callback("$result1, $result2") 是什么?

  • callback("$result1, $result2") 的作用是:
    • 生成一个字符串 "$result1, $result2"(比如 "Hello, World")。
    • 调用外部传入的 Lambda 代码块,并把这个字符串作为参数传递出去。

执行流程示例

假设:

class SomeClass {fun doSomething(): String = "Hello"
}class SomeOtherClass {fun doSomething(): String = "World"
}val someClass = SomeClass()
val someOtherClass = SomeOtherClass()

那么 doWork 执行后:

doWork { result -> println("回调结果: $result") }

会输出:

回调结果: Hello, World

总结

  1. doWork 方法执行后,someClass.doSomething()someOtherClass.doSomething() 生成两个字符串。
  2. callback("$result1, $result2") 将它们拼接,并调用外部 Lambda 代码块,把结果传出去。
  3. result 是 Lambda 代码块接收的参数,即 "Hello, World" 这样的字符串。
  4. viewModel.doWork 调用时,最终 TextView 显示 "ViewModel: Hello, World"

这种方式适用于异步任务或解耦逻辑的情况,比如 网络请求、数据库操作、后台计算等,执行完成后用回调通知 UI 层更新数据。

四 手动 clean + build

Build → Clean Project
Build → Rebuild Project

五 Android Hilt 入门教程(补充)

Hilt 是 Android 官方推荐的 依赖注入框架,它基于 Dagger,简化了依赖管理,适用于 MVVM 架构,提高了代码的可维护性。


1️⃣ 为什么要用 Hilt?

在 Android 开发中,们通常需要手动创建和管理对象,例如 ViewModelRepositoryRetrofit 等。Hilt 可以自动管理这些对象的创建和生命周期,让们专注于业务逻辑,而不是手动实例化对象。

Hilt 的优点:
✔️ 自动管理依赖,避免手动创建实例
✔️ ViewModel 支持,与 Jetpack 组件无缝集成
✔️ 作用域管理,不同组件(Activity、Fragment)能获得合适的对象
✔️ 简化 Dagger 依赖注入,代码更简洁


2️⃣ Hilt 的基本使用

📌(1)添加 Hilt 依赖

与第一点相同

plugins {id("com.android.application")id("kotlin-android")id("kotlin-kapt")id("com.google.dagger.hilt.android")
}android {namespace 'com.test.hiltstudy'compileSdk 35defaultConfig {applicationId "com.test.hiltstudy"minSdk 24targetSdk 35versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}
}Allow references to generated code
//kapt {
//    correctErrorTypes true
//}dependencies {implementation libs.androidx.core.ktximplementation libs.androidx.appcompatimplementation libs.materialimplementation libs.androidx.activityimplementation libs.androidx.constraintlayouttestImplementation libs.junitandroidTestImplementation libs.androidx.junitandroidTestImplementation libs.androidx.espresso.core// Hilt Dependenciesimplementation("com.google.dagger:hilt-android:2.51.1")kapt("com.google.dagger:hilt-android-compiler:2.51.1")// Fragment KTX for viewModels() delegateimplementation("androidx.fragment:fragment-ktx:1.6.2")// ViewModel
//    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
//    implementation("androidx.activity:activity-ktx:1.8.1")
//retrofitimplementation("com.squareup.retrofit2:converter-gson:2.9.0")}

📌(2)初始化 Hilt

AndroidManifest.xml

<applicationandroid:name=".MyApplication"...>
</application>

然后创建 MyApplication.kt

@HiltAndroidApp
class MyApplication : Application()

🔹 @HiltAndroidApp 用于初始化 Hilt,它会在 App 启动时配置依赖注入。


📌(3)在 Activity/Fragment 使用 Hilt

在 Activity 里启用 Hilt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入
}

🔹 @AndroidEntryPoint 标记 Activity 以支持 Hilt
🔹 @Inject lateinit var someClass: SomeClass 直接注入对象

在 Fragment 里启用 Hilt
@AndroidEntryPoint
class MainFragment : Fragment() {@Injectlateinit var someRepository: SomeRepository
}

💡 Activity 和 Fragment 都必须加 @AndroidEntryPoint 才能使用 Hilt 注入的对象!


📌(4)在 ViewModel 里使用 Hilt

@HiltViewModel
class MainViewModel @Inject constructor(private val repository: SomeRepository
) : ViewModel() {fun fetchData() = repository.getData()
}

ActivityFragment 里:

private val viewModel: MainViewModel by viewModels()

🔹 Hilt 自动创建 MainViewModel,不用 ViewModelProvider 手动实例化。


📌(5)创建 Hilt 模块(Module)

如果 SomeRepository 不能用 @Inject 直接构造,比如 Retrofit,们需要 使用 Module 提供实例

@Module
@InstallIn(SingletonComponent::class) // 作用于整个应用生命周期
object AppModule {@Provides@Singletonfun provideRetrofit(): Retrofit {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build()}@Provides@Singletonfun provideApiService(retrofit: Retrofit): ApiService {return retrofit.create(ApiService::class.java)}
}

🔹 @Module 标记为 Hilt 模块
🔹 @Provides 提供依赖
🔹 @Singleton 表示单例


3️⃣ Hilt 作用域

作用域说明示例
@Singleton全局单例,应用级共享Retrofit、数据库
@ActivityScoped只在 Activity 里共享共享 ViewModel
@ViewModelScoped只在 ViewModel 里共享Repository

4️⃣ Hilt 实战示例

1️⃣ 创建一个 Repository

class SomeRepository @Inject constructor() {fun getData(): String = "Hello from Repository"
}

2️⃣ 在 ViewModel 里注入

@HiltViewModel
class MainViewModel @Inject constructor(private val repository: SomeRepository
) : ViewModel() {fun fetchData(): String = repository.getData()
}

3️⃣ 在 Activity 里获取数据

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<TextView>(R.id.textView).text = viewModel.fetchData()}
}

✅ 运行后,TextView 显示 "Hello from Repository" 🎉


5️⃣ 总结

🔹 @HiltAndroidApp 让应用支持 Hilt
🔹 @AndroidEntryPoint 用于 Activity/Fragment
🔹 @HiltViewModel 用于 ViewModel
🔹 @Inject 直接注入类实例
🔹 @Module + @Provides 提供无法直接注入的对象(如 Retrofit)
🔹 @Singleton@ActivityScoped 控制对象生命周期

Hilt 让 依赖注入变得简单高效,可以自动管理对象,提升代码的可维护性。

五 为什么MainActivity 等类都必须写Hilt注解

  1. 当在 MainActivity 中使用 by viewModels() 时,Android 系统需要创建 MainViewModel 的实例
  2. MainViewModel 的构造函数需要一个 SomeRepository 参数
  3. 由于 SomeRepository 使用了 @Inject 注解,它只能通过 Hilt 的依赖注入系统来创建和管理

这就造成了一个依赖链:

  • MainActivity 需要 MainViewModel
  • MainViewModel 需要 SomeRepository
  • SomeRepository 由 Hilt 管理

所以当使用了 Hilt 来管理某个依赖(如 SomeRepository)时,所有需要使用这个依赖的类(如 MainViewModel)也必须通过 Hilt 来管理。这不是"强行绑定",而是依赖注入系统工作的必然要求。

如果不想使用 Hilt,需要:

  1. 移除 SomeRepository@Inject 注解
  2. 手动创建 SomeRepositoryMainViewModel 的实例
  3. 实现自定义的 ViewModelFactory

但这样会失去依赖注入带来的好处,如:

  • 依赖的自动管理
  • 生命周期的自动处理
  • 测试时依赖的容易替换
  • 代码的解耦

Hilt 管理对象的原理

Hilt 是基于 Dagger 的 依赖注入(Dependency Injection, DI)框架。它在编译期生成代码,自动管理对象的创建、注入和生命周期。

1️⃣ 自动管理依赖(对象创建)原理

当写:

class MyRepository @Inject constructor(private val apiService: ApiService
)

Hilt 会在 编译期生成一段 Dagger 代码,负责:

  • 创建 MyRepository
  • 自动找到 ApiService 的实例(如果也可以被 @Inject@Provides

👉 总结:
Hilt 使用 @Inject@Module + @Provides 来定义 对象之间的依赖关系图,并在编译时生成创建这些对象的代码。


2️⃣ 生命周期的自动处理

Hilt 把依赖对象和 Android 组件的生命周期绑定在一起,通过作用域注解(Scope)来完成。

🧩 作用域示例:
注解生命周期示例
@Singleton应用级别(Application 生命周期)Retrofit、Room
@ActivityScoped绑定到某个 Activity 生命周期当前 Activity 的共享依赖
@ViewModelScopedViewModel 生命周期当前 ViewModel 独享的对象
✅ 原理:

Hilt 在每个作用域下生成一个 Dagger 组件(Component):

  • SingletonComponent 对应 Application
  • ActivityComponent 对应 Activity
  • ViewModelComponent 对应 ViewModel

这些组件管理它们生命周期内的对象,只要组件存在,对象就一直存活;组件销毁,对象就自动释放。


3️⃣ 测试时依赖容易替换(可插拔)

Hilt 支持测试环境下 替换真实依赖为 Mock 或 Fake,这是 DI 的巨大优势。

✅ 替换方式:
@HiltAndroidTest
@UninstallModules(AppModule::class) // 卸载正式模块
class MyTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApi(): ApiService = FakeApiService()}
}

✅ 测试时,Hilt 用 TestModule 替换 AppModule,让测试逻辑而不是网络。


4️⃣ 解耦代码的核心原理

✅ 传统写法(耦合):
val repo = MyRepository(ApiService())
  • MyRepository 硬编码依赖了 ApiService,不利于替换、扩展、测试。
✅ Hilt 写法(解耦):
class MyRepository @Inject constructor(private val api: ApiService)
  • MyRepository 只依赖 抽象接口
  • ApiService 是由外部(Hilt)提供,未来替换为 FakeApiService 不用改业务逻辑
  • 解耦 = 高扩展性 + 高可测试性

🔧 总结原理图(类比管道工厂)

Hilt 功能原理类比
自动注入编译期生成依赖图自动搭建水管连接
生命周期管理每个作用域有专属组件管理对象活水池(组件)存在水就流动(对象存活)
测试替换支持模块替换换水源(Fake)测试流速(逻辑)
解耦结构依赖抽象、注入实现插拔模块化水管,便于维护

🚀 总结一句话:

Hilt = 编译期生成对象工厂 + 生命周期管家 + 解耦利器 + 测试友好助手,让写少但可维护性更高的代码。

六 Hilt 依赖注入结构图解

🧠 Hilt 架构核心

   +---------------------------+|      Application          ||  (HiltApplication class)  ||        @HiltAndroidApp    |+---------------------------+|v+---------------------------+| SingletonComponent        || @InstallIn(Singleton...)  || -> Retrofit, Room, Repo   |+---------------------------+|v+---------------------------+| ActivityComponent         || @InstallIn(Activity...)   || -> Activity 作用域对象     |+---------------------------+|v+---------------------------+| ViewModelComponent        || @HiltViewModel            || -> ViewModel 的依赖        |+---------------------------+|v+---------------------------+| FragmentComponent         || @AndroidEntryPoint        || -> Fragment 注入依赖       |+---------------------------+
当然可以!下面是 **Hilt 的内部结构原理图解** 的 `.md`(Markdown)格式说明,适合用于技术文档、GitHub README 或团队协作文档中:---​```md
# 🛠️ Hilt 依赖注入结构图解## 🧠 Hilt 架构核心​```plaintext+---------------------------+|      Application          ||  (HiltApplication class)  ||        @HiltAndroidApp    |+---------------------------+|v+---------------------------+| SingletonComponent        || @InstallIn(Singleton...)  || -> Retrofit, Room, Repo   |+---------------------------+|v+---------------------------+| ActivityComponent         || @InstallIn(Activity...)   || -> Activity 作用域对象     |+---------------------------+|v+---------------------------+| ViewModelComponent        || @HiltViewModel            || -> ViewModel 的依赖        |+---------------------------+|v+---------------------------+| FragmentComponent         || @AndroidEntryPoint        || -> Fragment 注入依赖       |+---------------------------+

🧩 作用域绑定关系

组件类型对应生命周期示例依赖项
SingletonComponentApplication 全局单例Retrofit、数据库等
ActivityComponent每个 Activity 独立当前 Activity 的共享依赖
ViewModelComponent每个 ViewModel 独立仓库、业务类
FragmentComponent每个 Fragment 独立当前 Fragment 的依赖

🔄 流程示意(依赖注入过程)

1. App 启动时,Hilt 生成 SingletonComponent
2. Activity 启动时,注入 ActivityComponent 作用域依赖
3. Fragment 加载时,注入 FragmentComponent 作用域依赖
4. ViewModel 被创建时,注入 ViewModelComponent 中依赖
5. 每个 Component 都可以从其上层 Component 获取依赖

✅ 示例:自动注入过程

// 注入 ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()
}// 提供依赖
@HiltViewModel
class MainViewModel @Inject constructor(private val repo: SomeRepository
) : ViewModel()// 仓库依赖提供
class SomeRepository @Inject constructor(private val api: ApiService
)

🧪 测试支持

@HiltAndroidTest
@UninstallModules(AppModule::class)
class MyTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApi(): ApiService = FakeApiService()}
}

八 Hilt为什么是解耦利器 和测试友好助手

Hilt 之所以被称为 “解耦利器”“测试友好助手”,是因为它能让 类之间的依赖关系更加松散,并且 支持在测试时轻松替换依赖

我们从 解耦(Decoupling)测试友好(Testability) 两个方面分别解释,并提供示例代码来说明。


🎯 1. Hilt 是如何解耦代码的?

✅ 传统写法(紧耦合,难以扩展)

class MyRepository {private val apiService = ApiService()  // 直接创建实例(强依赖)fun fetchData(): String {return apiService.getData()}
}

问题

  • MyRepository 直接依赖 ApiService,导致:
    1. 难以替换(如果要改用 FakeApiService 进行测试,就得修改 MyRepository 代码)
    2. 扩展性差(如果 ApiService 需要不同的实现方式,就得改 MyRepository
    3. 不适合单元测试(不能注入模拟数据)

✅ 使用 Hilt 进行解耦

class MyRepository @Inject constructor(private val apiService: ApiService) {fun fetchData(): String {return apiService.getData()}
}

Hilt 提供的 ApiService 实例

@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return RealApiService()}
}

解耦优势

  1. MyRepository 只依赖 ApiService 抽象,不关心 ApiService 具体是怎么来的
  2. 可以轻松替换 ApiService(比如切换到 FakeApiService 进行测试)
  3. 代码更清晰,职责更明确(Hilt 负责管理依赖,不再手动 new

🔬 2. Hilt 是如何让测试变得更简单的?

Hilt 允许我们在测试时 替换真实依赖,避免复杂的网络请求、数据库操作等,从而更快、更稳定地测试业务逻辑。

✅ 1. 不使用 Hilt,测试困难

@Test
fun testFetchData() {val repo = MyRepository(ApiService())  // 依赖真实的 ApiServiceval result = repo.fetchData()assertEquals("Expected Data", result)  // 可能失败,因为是真实数据
}

问题

  • MyRepository 无法使用 Mock 依赖
  • 每次测试都会访问真实 API(影响速度、可能失败)
  • 代码可测试性 非常低

✅ 2. 使用 Hilt 轻松替换依赖

🛠️ 在测试中提供 FakeApiService

@HiltAndroidTest
@UninstallModules(AppModule::class) // 先卸载正式模块
class MyRepositoryTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApiService(): ApiService {return object : ApiService {override fun getData(): String {return "Fake Data"}}}}@Injectlateinit var repository: MyRepository@get:Rulevar hiltRule = HiltAndroidRule(this)@Beforefun setup() {hiltRule.inject()  // 让 Hilt 注入测试依赖}@Testfun testFetchData() {val result = repository.fetchData()assertEquals("Fake Data", result)  // 100% 可预测的测试结果}
}

测试优势

  1. 自动替换真实依赖(不再访问网络或数据库)
  2. 测试速度更快(不依赖外部服务)
  3. Mock 数据可预测(不会受外部 API 变动影响)

📌 总结

特点传统依赖方式使用 Hilt
代码解耦直接 new 对象,强依赖具体实现依赖抽象,Hilt 负责提供实现
可扩展性变更时需要修改多个类只需修改 @Module 提供的依赖
测试友好依赖真实 API,难以 Mock轻松替换 Mock 依赖,提高测试效率
代码可维护性依赖关系混乱,难以管理依赖关系清晰,代码模块化

🚀 一句话总结

Hilt = 解耦利器 + 测试友好助手,让的代码 更模块化、更易测试、更易维护!


九 Hilt为什么是对象工厂 和 生命周期管家 ?

Hilt 之所以是 对象工厂生命周期管家,是因为它能够 自动创建并管理依赖对象,并且可以 自动适配依赖对象的生命周期,避免手动管理带来的复杂性和潜在的内存泄漏。


🎭 1. Hilt 是对象工厂(自动创建并管理依赖对象)

在没有 Hilt 的情况下,我们通常需要手动创建对象:

class MyRepository {private val apiService = ApiService()  // 直接创建实例
}

问题

  • MyRepository 依赖 ApiService,必须手动 new,不灵活
  • 如果 ApiService 还依赖 Retrofit,就需要 new 多个对象,依赖链复杂

Hilt 作为对象工厂

Hilt 通过 @Module + @Provides@Inject 构造注入 自动创建对象:

class MyRepository @Inject constructor(private val apiService: ApiService) { }

Hilt 自动提供 ApiService 实例

@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}
}

🎯 关键点

  1. Hilt 自动创建 ApiService,并将其注入到 MyRepository
  2. 我们不需要手动 new,Hilt 充当工厂,自动提供对象
  3. 如果 ApiService 还有依赖(如 Retrofit),Hilt 也会自动解析并注入

🕰️ 2. Hilt 是生命周期管家(自动管理对象生命周期)

在 Android 开发中,不同作用域的对象需要不同的生命周期,比如:

  • Application 级别的单例(整个应用共享)
  • Activity 级别的实例(Activity 销毁时自动清理)
  • Fragment 级别的实例(Fragment 关闭时释放)

❌ 传统方式:手动管理生命周期

class MainActivity : AppCompatActivity() {private val repository = MyRepository(ApiService()) // 手动创建,难以管理
}

问题

  • 全局变量会导致内存泄漏
  • Activity 重建(如旋转屏幕)后,数据可能丢失
  • 手动管理生命周期非常繁琐

Hilt 自动管理生命周期

Hilt 通过作用域(@InstallIn(Component::class))自动匹配生命周期:

🎯 Application 作用域(全局单例)

@InstallIn(SingletonComponent::class) // Application 级别
@Module
object AppModule {@Provides@Singletonfun provideMyRepository(apiService: ApiService): MyRepository {return MyRepository(apiService)}
}
  • 全局单例SingletonComponent 作用域下的对象,整个应用生命周期内存储
  • 避免重复创建:所有使用 MyRepository 的地方,都共享同一个实例

🎯 Activity 作用域(Activity 级别)

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels() // Hilt 自动管理生命周期
}
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
  • @HiltViewModel 绑定 ViewModel 生命周期,当 Activity 关闭时,ViewModel 也会自动销毁
  • MyRepository 仍然是 Singleton 作用域的,所以 MainViewModel 依赖它,但不会重复创建

🎯 Fragment 作用域

如果 Fragment 需要自己的 ViewModel

@AndroidEntryPoint
class MyFragment : Fragment() {private val viewModel: MyViewModel by viewModels()
}
@HiltViewModel
class MyViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
  • MyViewModel Fragment 绑定,Fragment 销毁时自动释放
  • 不会因为 Activity 变化导致数据丢失

📌 结论

特性传统方式使用 Hilt
对象管理手动 new,难以管理Hilt 自动创建并管理依赖
依赖关系需要手动传递依赖Hilt 通过 @Inject 自动注入
生命周期管理需要手动释放对象,避免内存泄漏Hilt 自动匹配对象生命周期
测试支持需要大量 MockHilt 允许轻松替换依赖

💡 总结

Hilt 作为 “对象工厂”,自动创建并管理依赖对象

Hilt 作为 “生命周期管家”,自动管理作用域,防止内存泄漏

这样,我们就能更专注于业务逻辑,而不用操心依赖创建和生命周期管理!

十 @Inject注解

@Inject 是 Hilt 依赖注入的核心注解,它的作用是 让 Hilt 知道如何创建和提供一个类的实例,从而 自动管理对象的依赖关系。提到的两种使用方式(构造函数注入字段注入)确实是 @Inject 的两个关键用途,下面详细解释。


📌 1. @Inject 作用之一:构造函数注入

构造函数注入(Constructor Injection)用于 告诉 Hilt 如何创建一个类的实例。当一个类的构造函数上加上 @Inject,Hilt 就会自动知道如何实例化它。

✅ 示例

class SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}
  • @Inject constructor() 告诉 Hilt 这个类可以被自动创建,无需手动 new SomeClass()
  • 任何需要 SomeClass 的地方,Hilt 都可以自动提供它
  • 适用于 无状态类(即不需要复杂的初始化)

🚀 使用 @Inject 的优势

无需手动 new 对象,Hilt 负责实例化
减少样板代码,避免工厂模式(Factory)或手写依赖注入
保证依赖一致性,不会意外创建多个 SomeClass 实例


📌 2. @Inject 作用之二:字段注入

字段注入(Field Injection)用于 在类内部自动注入依赖对象,通常用于 ActivityFragmentViewModel,因为它们的实例是由 Android 框架创建的,不能使用构造函数注入。

✅ 示例

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 使用被 Hilt 自动注入的对象Log.d("HiltExample", someClass.doSomething()) // 输出 "Hello Hilt!"}
}

📌 关键点

  1. @Inject lateinit var someClass: SomeClass
    • 让 Hilt 自动创建 SomeClass 实例,并注入到 someClass 变量中
    • 不需要 new SomeClass()
  2. @AndroidEntryPoint 必须加在 ActivityFragment,否则 Hilt 无法注入
    • 这是因为 ActivityFragment 由 Android 框架管理,Hilt 需要特殊处理它们的依赖注入

🚀 使用 @Inject 的优势

Hilt 自动创建并注入实例,无需手动初始化
避免 lateinit 为空的问题,Hilt 负责对象生命周期
简化依赖管理,代码更清晰、可维护性更强


📌 3. @Inject 与 Hilt 作用域

不同的 @Inject 依赖可以拥有不同的生命周期

@Singleton
class SomeSingletonClass @Inject constructor()
  • 这个 SomeSingletonClass 只会被创建一次,整个应用生命周期都能共享
  • Hilt 自动管理它的生命周期,不会意外地创建多个实例

不同作用域示例:

@ActivityScoped
class SomeActivityScopedClass @Inject constructor()
  • ActivityScoped每个 Activity 会有自己的实例
  • SingletonComponent全局单例
  • ViewModelScoped与 ViewModel 生命周期一致

📌 4. @Inject 不能用于接口,需要 @Module 提供

如果 @Inject 用在 接口 上,会报错:

interface ApiService {fun fetchData(): String
}

❌ 直接 @Inject 不行:

class ApiServiceImpl @Inject constructor() : ApiService {override fun fetchData() = "API Data"
}

👉 必须使用 @Module 提供接口实例

@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Providesfun provideApiService(): ApiService {return ApiServiceImpl()}
}

📌 关键点

  • 如果是普通类,@Inject constructor() 就够了
  • 如果是接口,必须用 @Module@Provides 提供

🎯 结论

方式使用场景作用
@Inject constructor()普通类让 Hilt 知道如何创建这个类
@Inject lateinit varActivity、Fragment、ViewModel让 Hilt 自动注入对象实例
@Module + @Provides接口或第三方库让 Hilt 提供无法直接 @Inject 的对象

🚀 一句话总结

@Inject 让 Hilt 知道如何创建对象,而 @Inject lateinit var 让 Hilt 自动注入对象!


十一 Hilt其他注解

Android Hilt 中,除了 @Inject 之外,还有多个核心注解,它们负责不同的依赖注入功能,包括作用域管理、模块提供依赖、绑定接口、生命周期管理等。以下是 Hilt 的核心注解及其详细解析,并附上代码示例。


📌 1. @HiltAndroidApp

作用

  • 标记 Application 类,让 Hilt 生成依赖注入的代码
  • 必须Application 类上使用

✅ 示例

@HiltAndroidApp
class MyApplication : Application()

🚀 关键点

✅ Hilt 会在应用启动时初始化依赖注入
✅ 生成 Hilt_MyApplication 代码,Hilt 依赖的入口
必须加,否则 Hilt 无法工作


📌 2. @AndroidEntryPoint

作用

  • 用于 ActivityFragmentService,让它们支持 Hilt 依赖注入
  • 必须加,否则 Hilt 无法注入对象

✅ 示例

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入
}

🚀 关键点

ActivityFragmentService 必须加,否则 @Inject 不会生效
✅ Hilt 会自动在内部生成依赖注入代码
Fragment 依赖的 Activity 也必须有 @AndroidEntryPoint,否则会崩溃


📌 3. @Inject

作用

  • 用于 构造函数字段,让 Hilt 知道如何创建和注入对象

✅ 示例

构造函数注入

class SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}

字段注入

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass
}

🚀 关键点

构造函数上加 @Inject,Hilt 知道如何创建对象
字段加 @Inject,Hilt 会自动提供依赖


📌 4. @Module + @InstallIn

作用

  • 提供无法直接 @Inject 的对象(如接口、第三方库)
  • 定义依赖的作用域

✅ 示例

@Module
@InstallIn(SingletonComponent::class) // 全局单例
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}
}

🚀 关键点

@Module 让 Hilt 知道这里提供依赖
@InstallIn 确定依赖的作用域(SingletonComponent 表示全局单例)


📌 5. @Provides

作用

  • 提供对象实例(适用于无法 @Inject 的情况,如第三方库)

✅ 示例

@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Providesfun provideSomeClass(): SomeClass {return SomeClass()}
}

🚀 关键点

如果 SomeClass 不能 @Inject,就用 @Provides 提供
返回类型就是 Hilt 提供的类型


📌 6. @Binds

作用

  • 用于接口的实现绑定
  • @Provides 更高效(少了一次方法调用)

✅ 示例

interface ApiService {fun fetchData(): String
}class ApiServiceImpl @Inject constructor() : ApiService {override fun fetchData() = "API Data"
}@Module
@InstallIn(SingletonComponent::class)
abstract class AppModule {@Bindsabstract fun bindApiService(impl: ApiServiceImpl): ApiService
}

🚀 关键点

@Binds 只能用于 abstract 方法,不能有逻辑
@Provides 更高效,但 @Provides 更灵活


📌 7. 作用域注解

作用

  • 控制 对象的生命周期,防止重复创建
  • 适用于 @Provides@Inject 提供的对象

✅ 示例

@Singleton
class SomeSingletonClass @Inject constructor()
作用域适用范围生命周期
SingletonComponent全局应用生命周期
ActivityRetainedComponentViewModelActivity 重新创建时依然存在
ActivityComponentActivityActivity 销毁时释放
FragmentComponentFragmentFragment 销毁时释放

📌 8. @HiltViewModel

作用

  • 让 ViewModel 支持 Hilt 注入
  • 简化 ViewModel 创建

✅ 示例

@HiltViewModel
class MainViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()
}

🚀 关键点

@HiltViewModel 必须配合 @AndroidEntryPointActivityFragment
ViewModel 不用手动创建,Hilt 自动管理


📌 9. @EntryPoint

作用

  • 用于无法使用 @AndroidEntryPoint 的类
  • ContentProviderBroadcastReceiver

✅ 示例

@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyEntryPoint {fun getSomeClass(): SomeClass
}// 使用 EntryPoint
val someClass = EntryPointAccessors.fromApplication(context, MyEntryPoint::class.java).getSomeClass()

🚀 关键点

适用于无法直接 @Inject 的情况
Hilt 依然能提供依赖


🎯 结论

注解作用
@HiltAndroidApp让 Hilt 初始化依赖注入(必须加在 Application
@AndroidEntryPointActivityFragmentService 支持 Hilt
@Inject构造函数注入 & 字段注入
@Module + @InstallIn提供无法 @Inject 的依赖
@Provides直接提供实例(如第三方库)
@Binds绑定接口实现(比 @Provides 高效)
@Singleton作用域管理(全局单例)
@HiltViewModelHilt ViewModel 支持
@EntryPoint用于 BroadcastReceiverContentProvider

🚀 总结:Hilt 通过 @Inject@Module@Provides 等注解,让 对象创建 & 生命周期管理 自动化,大幅减少样板代码,提高可维护性!

参考

google Hilt 教程

相关文章:

Android Hilt 教程

Android Hilt 教程 —— 一看就懂&#xff0c;一学就会 1. 什么是 Hilt&#xff1f;为什么要用 Hilt&#xff1f; Hilt 是 Android 官方推荐的 依赖注入&#xff08;DI&#xff09;框架&#xff0c;基于 Dagger 开发&#xff0c;能够大大简化依赖注入的使用。 为什么要用 Hi…...

高德地图 3D 渲染-区域纹理图添加

引入-初始化地图&#xff08;关键代码&#xff09; // 初始化页面引入高德 webapi -- index.html 文件 <script src https://webapi.amap.com/maps?v2.0&key您申请的key值></script>// 添加地图容器 <div idcontainer ></div>// 地图初始化应该…...

K8S核心技术点

Pod&#xff0c;Service和Deployment的关系 Pod&#xff1a;Kubernetes 中最小的部署单元&#xff0c;用于运行容器化应用。 Service&#xff1a;提供服务发现和负载均衡&#xff0c;为 Pod 提供稳定的网络端点&#xff0c;ClusterIP&#xff0c;NodePort&#xff0c;LoadBala…...

Spring Boot 与 TDengine 的深度集成实践(二)

创建数据模型 定义实体类 在完成数据库连接配置后&#xff0c;我们需要创建与 TDengine 表对应的 Java 实体类。实体类是 Java 对象与数据库表之间的映射&#xff0c;通过定义实体类&#xff0c;我们可以方便地在 Java 代码中操作数据库中的数据&#xff0c;实现数据的持久化…...

搭建hadoop集群模式并运行

3.1 Hadoop的运行模式 先去官方看一看Apache Hadoop 3.3.6 – Hadoop: Setting up a Single Node Cluster. 本地模式&#xff1a;数据直接存放在Linux的磁盘上&#xff0c;测试时偶尔用一下 伪分布式&#xff1a;数据存放在HDFS&#xff0c;公司资金不足的时候用 完全分布式&a…...

Qt实现鼠标右键弹出弹窗退出

Qt鼠标右键弹出弹窗退出 1、鼠标右键实现1.1 重写鼠标点击事件1.2 添加头文件1.3 添加定义2、添加菜单2.1添加菜单头文件2.2创建菜单对象2.3 显示菜单 3、添加动作3.1添加动作资源文件3.2 添加头文件3.3 创建退出动作对象3.4菜单添加动作对象 4、在当前鼠标位置显示菜单4.1当前…...

Spring 服务调用接口时,提示You should be redirected automatically to target URL:

问题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href"http://xxx/api/v1/branch…...

Springboot整合Mybatis+Maven+Thymeleaf学生成绩管理系统

前言 该系统为学生成绩管理系统&#xff0c;可以当作学习参考&#xff0c;也可以成为Spirng Boot初学者的学习代码&#xff01; 系统描述 学生成绩管理系统提供了三种角色&#xff1a;学生&#xff0c;老师&#xff0c;网站管理员。主要实现的功能如下&#xff1a; 登录 &a…...

马井堂js设置倒计时页面

js-倒计时页面 提示&#xff1a;这里简述项目相关背景&#xff1a; 例如&#xff1a;项目场景&#xff1a;倒计时需求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible&…...

C#里第一个WPF程序

WPF程序对界面进行优化,但是比WINFORMS的程序要复杂很多, 并且界面UI基本上不适合拖放,所以需要比较多的时间来布局界面, 产且需要开发人员编写更多的代码。 即使如此,在面对诱人的界面表现, 随着客户对界面的需求提高,还是需要采用这样的方式来实现。 界面的样式采…...

【Java设计模式】第5章 工厂方法模式讲解

5. 工厂方法模式 5.1 工厂方法讲解 定义:定义一个创建对象的接口,由子类决定实例化的类,将对象创建延迟到子类。适用场景: 创建对象需要大量重复代码。客户端不依赖具体产品的创建细节。优点: 符合开闭原则,新增产品只需扩展子类。客户端仅依赖抽象接口,不依赖具体实现…...

PyTorch 生态迎来新成员:SGLang 高效推理引擎解析

SGLang 现已正式融入 PyTorch 生态系统&#xff01;此次集成确保了 SGLang 符合 PyTorch 的技术标准与最佳实践&#xff0c;为开发者提供了一个可靠且社区支持的框架&#xff0c;助力大规模语言模型&#xff08;LLM&#xff09;实现高效且灵活的推理。 如需深入了解 PyTorch…...

时序数据库 TDengine Cloud 私有连接实战指南:4步实现数据安全传输与成本优化

小T导读&#xff1a;在物联网和工业互联网场景下&#xff0c;企业对高并发、低延迟的数据处理需求愈发迫切。本文将带你深入了解 TDengineCloud 如何通过全托管服务与私有连接&#xff0c;帮助企业实现更安全、更高效、更低成本的数据采集与传输&#xff0c;从架构解析到实际配…...

微服务注册中心选择指南:Eureka vs Consul vs Zookeeper vs Nacos

文章目录 引言微服务注册中心概述什么是服务注册与发现选择注册中心的标准 常见的微服务注册中心1. Eureka1.1 理论基础1.2 特点1.3 示例代码 2. Consul2.1 理论基础2.2 特点2.3 示例代码 3. Zookeeper3.1 理论基础3.2 特点3.3 示例代码 4. Nacos4.1 理论基础4.2 特点4.3 示例代…...

Java - WebSocket配置及使用

引入依赖 Spring Boot 默认支持 WebSocket&#xff0c;但需要引入 spring-boot-starter-websocket 依赖&#xff0c;然后重新构建项目 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</arti…...

厦门未来之音:科技与自然共舞的奇幻篇章

故事背景 故事发生在中国福建厦门&#xff0c;描绘未来城市中科技与传统文化深度融合的奇景。通过六大创新场景展现人与自然、历史与未来的和谐共生&#xff0c;市民在智能设施中感受文化传承的力量。 故事内容 从鼓浪屿的声波音乐栈道到BRT天桥上的空中茶园&#xff0c;从修复…...

React 列表与 Keys 的深入探讨

React 列表与 Keys 的深入探讨 在 React 中,列表渲染是一个常见的操作,而 Keys 是在列表渲染中一个非常重要的概念。本文将深入探讨 React 列表与 Keys 的关系,帮助开发者更好地理解并运用它们。 引言 React 是一个用于构建用户界面的 JavaScript 库,它的虚拟 DOM 和组件…...

【Python】Python 100题 分类入门练习题 - 新手友好

Python 100题 分类入门练习题 - 新手友好篇 - 整合篇 一、数学问题题目1&#xff1a;组合数字题目2&#xff1a;利润计算题目3&#xff1a;完全平方数题目4&#xff1a;日期天数计算题目11&#xff1a;兔子繁殖问题题目18&#xff1a;数列求和题目19&#xff1a;完数判断题目21…...

2025年Python的主要应用场景

李升伟 编译 Python在2025年仍是最受欢迎和强大的编程语言之一。其简洁易读的语法以及庞大的库生态系统&#xff0c;使其成为各行业开发者的首选。无论是构建复杂的数据管道&#xff0c;还是自动化重复性任务&#xff0c;Python都能提供广泛的应用场景&#xff0c;以实现快速、…...

PyTorch中的Flatten

在 PyTorch 中&#xff0c;Flatten 操作是将多维张量转换为一维向量的重要操作&#xff0c;常用于卷积神经网络(CNN)的全连接层之前。以下是 PyTorch 中实现 Flatten 的各种方法及其应用场景。 一、基本 Flatten 方法 1. 使用 torch.flatten() 函数 import torch# 创建一个4…...

深入浅出动态规划:从基础到蓝桥杯实战(Java版)

引言&#xff1a;为什么你需要掌握动态规划&#xff1f; 动态规划&#xff08;DP&#xff09;是算法竞赛和面试中的常客&#xff0c;不仅能大幅提升解题效率&#xff08;时间复杂度通常为O(n)或O(n)&#xff09;[4]&#xff0c;更是解决复杂优化问题的利器。统计显示&#xff…...

VS Code-i18n Ally国际化插件

前言 本文借鉴&#xff1a;i18n Ally 插件帮你轻松搞定国际化需求-按模块划分i18n Ally 是一款 VS Code 插件&#xff0c;它能通过可视 - 掘金本来是没有准备将I18n Ally插件单独写一个博客的&#xff0c;但是了解过后&#xff0c;功能强大&#xff0c;使用方便&#xff0c;解决…...

YOLO中mode.predict()参数详解

Inference arguments: ArgumentTypeDefaultDescriptionsourcestr‘ultralytics/assets’指定推理的数据源。可以是图像路径、视频文件、目录、URL 或实时源的设备 ID。支持多种格式和数据源&#xff0c;可在不同类型的输入中灵活应用。conffloat0.25设置检测的最小置信度阈值。…...

收敛算法有多少?

收敛算法是指在迭代计算过程中&#xff0c;能够使序列或函数逐渐逼近某个极限值或最优解的算法。常见的收敛算法有以下几种&#xff1a; 梯度下降法&#xff08;Gradient Descent&#xff09; 原理&#xff1a;通过沿着目标函数的负梯度方向更新参数&#xff0c;使得目标函数…...

在亚马逊云科技上使用n8n快速构建个人AI NEWS助理

前言&#xff1a; N8n 是一个强大的工作流自动化工具&#xff0c;它允许您连接不同的应用程序、服务和系统&#xff0c;以创建自动化工作流程&#xff0c;并且采用了开源MIT协议&#xff0c;可以放心使用&#xff0c;他的官方网站也提供了很多的工作流&#xff0c;大家有兴趣的…...

STM32单片机入门学习——第27节: [9-3] USART串口发送串口发送+接收

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.08 STM32开发板学习——第27节: [9-3] USART串口发送&串口发送接收 前言开发板说…...

python 3.9 随机生成 以UTF-8 编码 的随机中文

理论实践 因为python3的默认编码为UTF-8&#xff0c;我们将‘浪’的utf8\u6d6a进行打印测试 print(\u6d6a) >>浪 中文匹配范围有两种 [\u4e00-\u9fa5]和[\u2E80-\u9FFF]&#xff0c;后者包括了日韩地区的汉字 由于utf采用16进制&#xff0c;则需要进行一个进制的变换&a…...

数字电子技术基础(四十)——使用Digital软件和Multisim软件模拟显示译码器

目录 1 使用Digital软件模拟显示译码器 1.1 原理介绍 1.2 器件选择 1.3 电路运行 1.4 结果分析 2 使用Multisim软件模拟显示译码器 2.1 器件选择 2.2 电路运行 1 使用Digital软件模拟显示译码器 1.1 原理介绍 7448常用于驱动7段显示译码器。如下所示为7448驱动BS201A…...

第十四届蓝桥杯大赛软件赛国赛C/C++研究生组

研究生C国赛软件大赛 题一&#xff1a;混乘数字题二&#xff1a;钉板上的正方形题三&#xff1a;整数变换题四&#xff1a;躲炮弹题五&#xff1a;最大区间 题一&#xff1a;混乘数字 有一点像哈希表&#xff1a; 首先定义两个数组&#xff0c;拆分ab和n 然后令n a*b 查看两个…...

innodb如何实现mvcc的

InnoDB 实现 MVCC&#xff08;多版本并发控制&#xff09;的机制主要依赖于 Undo Log&#xff08;回滚日志&#xff09;、Read View&#xff08;读视图&#xff09; 和 隐藏的事务字段。以下是具体实现步骤和原理&#xff1a; 1. 核心数据结构 InnoDB 的每一行数据&#xff08…...