0Pricing
Android Academy · 课时

使用 Hilt 进行依赖注入

使用 Hilt 简化依赖管理。使用 @HiltAndroidApp、@AndroidEntryPoint、@HiltViewModel、@Module、@Provides 和 @Singleton 作用域。

使用 Hilt 进行依赖注入 是 CoddyKit 上的免费 Android Academy 课时。 这是第 6 节课,共 6 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 6 节课。

什么是依赖注入?

依赖注入(DI)是指为对象提供它所需的内容,而不是让对象自行创建依赖项。

没有 DI 时,类会自行创建依赖项——耦合紧密且难以测试。有了 DI,依赖项会从外部注入——耦合松散,易于测试和替换。

手动 DI 与 Hilt

手动 DI 虽然可行,但项目规模扩大后会变得很麻烦:

// Manual DI — you create and pass everything:
val db = AppDatabase.getInstance(context)
val dao = db.userDao()
val repo = UserRepository(dao)
val factory = UserViewModel.Factory(repo)
val viewModel = ViewModelProvider(this, factory)[UserViewModel::class.java]

// With Hilt:
// Just annotate, Hilt does the wiring
@HiltViewModel
class UserViewModel @Inject constructor(private val repo: UserRepository) : ViewModel()

添加 Hilt

将 Hilt 添加到项目中:

// project/build.gradle:
buildscript {
    dependencies {
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.51'
    }
}

// app/build.gradle:
plugins {
    id 'com.google.dagger.hilt.android'
    id 'kotlin-kapt'
}

dependencies {
    implementation 'com.google.dagger:hilt-android:2.51'
    kapt 'com.google.dagger:hilt-android-compiler:2.51'
}

@HiltAndroidApp

使用 @HiltAndroidApp 为您的 Application 类添加注解。这是 Hilt 组件层次结构的入口点:

@HiltAndroidApp
class MyApp : Application()

// Also register in AndroidManifest.xml:
// <application android:name=".MyApp" ...>

@AndroidEntryPoint

为需要注入依赖项的 Activity、Fragment 和 Service 添加 @AndroidEntryPoint:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var analytics: AnalyticsService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        analytics.logEvent("app_open")
    }
}

@AndroidEntryPoint
class HomeFragment : Fragment() {
    // Fragment's parent Activity must also be @AndroidEntryPoint
}

@Inject — 构造函数注入

使用 @Inject 标记构造函数,告诉 Hilt 如何创建该类。Hilt 会自动解析所有参数:

class UserRepository @Inject constructor(
    private val userDao: UserDao,
    private val apiService: ApiService
) {
    suspend fun getUsers() = userDao.getAll()
    suspend fun syncFromNetwork() {
        val users = apiService.fetchUsers()
        userDao.insertAll(users)
    }
}

// Hilt sees UserRepository needs UserDao and ApiService,
// and automatically creates and injects them.

@HiltViewModel

使用 @HiltViewModel 为您的 ViewModel 添加注解,并使用 @Inject constructor。在 Fragment 中通过 by viewModels() 获取它:

@HiltViewModel
class UserViewModel @Inject constructor(
    private val repo: UserRepository
) : ViewModel() {

    val users = repo.getUsersFlow().asLiveData()
}

// In Fragment:
@AndroidEntryPoint
class UserFragment : Fragment() {
    private val viewModel: UserViewModel by viewModels()  // Hilt provides it
}

@Module 与 @Provides

当 Hilt 无法使用构造函数注入时(例如接口、第三方类),可以通过 @Module 提供实例:

@Module
@InstallIn(SingletonComponent::class)   // lives for app lifetime
object NetworkModule {

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

@Binds — 接口绑定

使用 @Binds 告诉 Hilt 某个接口应使用哪个实现:

interface AnalyticsService {
    fun logEvent(name: String)
}

class FirebaseAnalytics @Inject constructor() : AnalyticsService {
    override fun logEvent(name: String) { /* Firebase impl */ }
}

@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

    @Binds
    @Singleton
    abstract fun bindAnalytics(impl: FirebaseAnalytics): AnalyticsService
}

Hilt 作用域

作用域控制注入实例可以存活多长时间:

  • @Singleton — 在应用的整个生命周期内使用同一个实例(ApplicationComponent)
  • @ActivityRetainedScoped — 在配置更改后仍然存活
  • @ActivityScoped — 每个 Activity 使用一个实例
  • @FragmentScoped — 每个 Fragment 使用一个实例
  • @ViewModelScoped — 每个 ViewModel 使用一个实例

使用 Hilt 进行测试

使用 Hilt 的测试支持,在测试中用伪实现替换真实依赖项:

@HiltAndroidTest
class UserRepositoryTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)

    @Inject
    lateinit var repo: UserRepository

    @Before
    fun setUp() {
        hiltRule.inject()
    }

    @Test
    fun usersAreFetched() {
        assertNotNull(repo)
    }
}

快速检查

哪个注解会告诉 Hilt 为整个应用生成 DI 组件层次结构?

回顾:Hilt 依赖注入

Hilt 让 Android 中的 DI 几乎可以自动完成:

  • 在 Application 类上使用 @HiltAndroidApp
  • 在 Activity 和 Fragment 上使用 @AndroidEntryPoint
  • 对可注入的类使用 @Inject constructor
  • 对 ViewModel 使用 @HiltViewModel + @Inject constructor
  • 对第三方类和接口使用 @Module + @Provides
  • 使用 @Singleton 在整个应用中共享一个实例

下一节:使用 Firebase Cloud Messaging 推送通知。

常见问题解答

「使用 Hilt 进行依赖注入」课时是免费的吗?

是的 — 「使用 Hilt 进行依赖注入」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 6 节课。

「使用 Hilt 进行依赖注入」这节课中我会学到什么?

使用 Hilt 简化依赖管理。使用 @HiltAndroidApp、@AndroidEntryPoint、@HiltViewModel、@Module、@Provides 和 @Singleton 作用域。 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Android Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 6 节课,共 6 节。

「使用 Hilt 进行依赖注入」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Android Academy 课中编写并运行代码吗?

能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ViewModel 与 LiveData
  2. Room 数据库
  3. 协程与挂起函数
  4. 仓储模式
  5. Navigation 组件
  6. 使用 Hilt 进行依赖注入
← 返回 Android Academy