Jorgen's blog Jorgen's blog
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

jorgen

Love it, make mistakes, learn, keep grinding.
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Capacitor浅析
  • ADB调试
  • mlkit
  • face detection
  • Android中的Kotlin协程:告别回调地狱
  • Android性能优化实践与技巧
  • Android Jetpack Compose入门:构建现代UI的全新方式
  • Android Jetpack Compose入门与实践 - 构建现代Android UI
  • Android Jetpack Compose入门指南 - 构建现代UI的全新方式
  • Android Jetpack与架构组件-构建现代化应用
  • Android Jetpack架构组件:ViewModel与LiveData实战指南
  • Android Jetpack组件:构建现代Android应用的核心利器
  • Android Jetpack组件详解:构建现代化应用的核心
  • Android数据绑定与MVVM架构-构建现代化应用
  • Android架构组件:构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基石
  • Android架构组件与Jetpack-构建现代化应用的基础
  • Android架构设计之MVVM模式实战指南
  • 拥抱未来:Android Jetpack Compose入门指南
  • Android权限管理完全指南-从基础到实践
  • Android测试指南-从单元测试到UI测试的实践之路
  • Android依赖注入实战:从Dagger到Hilt的进化之路
    • 前言
    • 依赖注入的基本概念
    • Dagger:依赖注入的王者
      • Dagger的核心组件
      • Dagger的挑战
    • Hilt:为Android量身定制的DI框架
      • Hilt的核心优势
      • Hilt的基本使用
    • Hilt的关键组件
      • 1. @HiltAndroidApp
      • 2. @AndroidEntryPoint
      • 3. @Module 和 @InstallIn
      • 4. @ViewModelInject
      • 5. 限定符(Qualifiers)
    • Hilt的高级特性
      • 1. 作用域绑定
      • 2. 预定义绑定
      • 3. 多绑定
    • 实战案例:使用Hilt构建MVVM架构
      • 1. 添加依赖
      • 2. 创建数据层
      • 3. 创建ViewModel
      • 4. 创建UI层
      • 5. 配置Hilt Modules
    • Dagger迁移到Hilt的最佳实践
      • 1. 逐步迁移
      • 2. 保留Dagger组件
      • 3. 利用Hilt的测试支持
    • 结语
  • Android网络编程完全指南-从HTTP到Retrofit的实践之路
  • Android数据持久化完全指南-从SharedPreferences到Room数据库
  • Android多线程与并发处理完全指南-从Thread到协程的进阶之路
  • Android应用打包与发布全流程指南-从签名到上架的实战之路
  • Android安全完全指南-从基础防护到高级加密的实战之路
  • android
Jorgen
2023-11-15
目录

Android依赖注入实战:从Dagger到Hilt的进化之路

# 前言

作为一名Android开发者,你是否也曾陷入这样的困境:

"这个类需要另一个类的实例,我应该在哪里创建它?直接在构造函数里new吗?还是通过某个工厂方法?"

或者更糟的是:

"这个类的依赖太复杂了,构造函数参数已经多到数不清了..."

这些问题其实都指向同一个解决方案——依赖注入(Dependency Injection, DI)。🤔

提示

依赖注入是一种设计模式,它将组件的依赖关系从组件内部转移到外部,通过外部提供依赖的方式,使组件更加解耦、可测试和可维护。

在Android开发中,依赖注入框架帮助我们管理对象的生命周期和依赖关系,让代码更加清晰和可维护。今天,我们就来深入探讨Android中最流行的依赖注入框架:从Dagger到Hilt的进化之路。

# 依赖注入的基本概念

在开始之前,让我们先理解几个关键概念:

  • 依赖(Dependency):一个类需要另一个类来完成它的功能,这个被需要的类就是依赖。
  • 依赖注入(DI):不是让类自己创建依赖,而是由外部框架将依赖"注入"到类中。
// 传统方式 - 类自己创建依赖
class UserRepository {
    private val apiService = RetrofitClient.createApiService()
    
    fun fetchData(): String {
        return apiService.getData()
    }
}

// 依赖注入方式 - 依赖由外部提供
class UserRepository(private val apiService: ApiService) {
    fun fetchData(): String {
        return apiService.getData()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

通过这种方式,UserRepository不再关心ApiService如何创建,只需专注于自己的业务逻辑。🎯

# Dagger:依赖注入的王者

在Hilt出现之前,Dagger是Android开发中最流行的依赖注入框架。它是Square公司基于Java注解处理器开发的高性能DI框架。

# Dagger的核心组件

Dagger主要由以下几个核心组件组成:

  1. @Module:定义如何提供依赖的类
  2. @Provides:在@Module中标记提供依赖的方法
  3. @Inject:标记需要依赖的构造函数或字段
  4. @Component:连接提供方和使用方的接口
@Module
class NetworkModule {
    @Provides
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
            .create(ApiService::class.java)
    }
}

@Component(modules = [NetworkModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
}

class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var apiService: ApiService
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val appComponent = DaggerAppComponent.create()
        appComponent.inject(this)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# Dagger的挑战

尽管Dagger功能强大,但在Android项目中使用它也面临一些挑战:

  • 配置复杂:需要编写大量的Module和Component
  • 编译时间长:注解处理需要时间,大型项目可能需要几分钟
  • 学习曲线陡峭:概念多,配置复杂,新手容易迷失
  • Android特定支持不足:需要额外配置来支持Android组件的生命周期

# Hilt:为Android量身定制的DI框架

面对Dagger的挑战,Google与Square合作开发了Hilt——一个基于Dagger的、专为Android设计的依赖注入库。Hilt简化了Dagger在Android中的使用,提供了更简洁的API和更好的Android集成。

# Hilt的核心优势

  1. 自动生成组件:Hilt自动为Android组件创建相应的Hilt组件
  2. 简化配置:减少了大量样板代码
  3. 生命周期感知:自动管理依赖的生命周期
  4. 作用域绑定:将依赖与Android组件的生命周期绑定

# Hilt的基本使用

让我们看看如何用Hilt重写之前的例子:

// 定义接口
interface ApiService {
    fun getData(): String
}

// 实现接口
class ApiServiceImpl @Inject constructor() : ApiService {
    override fun getData(): String = "Data from API"
}

// 在ViewModel中使用
@HiltViewModel
class MainViewModel @Inject constructor(
    private val apiService: ApiService
) : ViewModel() {
    fun fetchData(): String = apiService.getData()
}

// 在Activity中使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        Log.d("MainActivity", viewModel.fetchData())
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

看到区别了吗?几乎不需要任何配置!Hilt会自动处理依赖的创建和注入。🚀

# Hilt的关键组件

# 1. @HiltAndroidApp

这是Hilt的入口点,需要在Application类上添加:

@HiltAndroidApp
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
    }
}
1
2
3
4
5
6

# 2. @AndroidEntryPoint

标记需要依赖注入的Android组件:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    // ...
}
1
2
3
4

支持的组件包括:

  • Application
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

# 3. @Module 和 @InstallIn

定义自定义依赖提供方式:

@Module
@InstallIn(ActivityComponent::class) // 限定作用域为Activity
object ActivityModule {
    @Provides
    fun provideString(): String = "Hello from ActivityModule"
}
1
2
3
4
5
6

# 4. @ViewModelInject

在ViewModel中注入依赖:

@HiltViewModel
class MyViewModel @ViewModelInject constructor(
    private val repository: MyRepository
) : ViewModel() {
    // ...
}
1
2
3
4
5
6

# 5. 限定符(Qualifiers)

当有多个相同类型的依赖时,使用限定符来区分:

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class AuthInterceptor

@Module
@InstallIn(ActivityComponent::class)
object NetworkModule {
    @Provides
    @AuthInterceptor
    fun provideAuthInterceptor(): Interceptor {
        return Interceptor { chain ->
            val request = chain.request()
                .newBuilder()
                .addHeader("Authorization", "Bearer token")
                .build()
            chain.proceed(request)
        }
    }
}

class MyViewModel @ViewModelInject constructor(
    @AuthInterceptor private val authInterceptor: Interceptor
) : ViewModel() {
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# Hilt的高级特性

# 1. 作用域绑定

Hilt将依赖与Android组件的生命周期绑定:

注解 绑定到的组件 生命周期
@Singleton ApplicationComponent Application
@ActivityRetainedScoped ActivityRetainingComponent Activity的onCreate到onDestroy
@ActivityScoped ActivityComponent Activity的onCreate到onDestroy
@FragmentScoped FragmentComponent Fragment的onAttach到onDetach
@ViewScoped ViewComponent View的onCreate到onDestroy

# 2. 预定义绑定

Hilt为Android组件提供了预定义绑定:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    // 获取Application实例
    private val application by inject<Application>()
    
    // 获取Activity
    private val activity by inject<Activity>()
    
    // 获取ApplicationContext
    private val context by inject<Context>()
    
    // 获取Resources
    private val resources by inject<Resources>()
    
    // 获取SupportFragmentManager
    private val supportFragmentManager by inject<FragmentManager>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 使用这些预定义绑定
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 3. 多绑定

将多个相同类型的依赖收集到一个集合中:

@Module
@InstallIn(ActivityComponent::class)
object BindingsModule {
    
    @Binds
    @IntoMap
    @ViewModelKey(UserViewModel::class)
    fun bindUserViewModel(viewModel: UserViewModel): ViewModel = viewModel
    
    @Binds
    @IntoMap
    @ViewModelKey(SettingsViewModel::class)
    fun bindSettingsViewModel(viewModel: SettingsViewModel): ViewModel = viewModel
}

@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

@HiltViewModel
class MainActivityViewModel @ViewModelInject constructor(
    @ViewModelKey(UserViewModel::class) private val userViewModel: ViewModel,
    @ViewModelKey(SettingsViewModel::class) private val settingsViewModel: ViewModel
) : ViewModel() {
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 实战案例:使用Hilt构建MVVM架构

让我们通过一个完整的示例,看看如何使用Hilt构建一个现代化的MVVM架构应用。

# 1. 添加依赖

首先,在app模块的build.gradle中添加Hilt依赖:

dependencies {
    implementation 'com.google.dagger:hilt-android:2.45'
    kapt 'com.google.dagger:hilt-compiler:2.45'
    
    // 如果使用Kotlin KAPT
    kapt 'androidx.hilt:hilt-compiler:1.0.0'
    
    // 如果使用Navigation Component
    implementation 'androidx.hilt:hilt-navigation-fragment:1.0.0'
}
1
2
3
4
5
6
7
8
9
10

# 2. 创建数据层

// Repository接口
interface UserRepository {
    suspend fun getUsers(): List<User>
}

// Repository实现
class UserRepositoryImpl @Inject constructor(
    private val apiService: ApiService,
    private val userDao: UserDao
) : UserRepository {
    
    override suspend fun getUsers(): List<User> {
        // 先从数据库获取
        val cachedUsers = userDao.getAllUsers()
        if (cachedUsers.isNotEmpty()) {
            return cachedUsers
        }
        
        // 如果数据库没有,从网络获取
        val remoteUsers = apiService.getUsers()
        userDao.insertAll(remoteUsers)
        return remoteUsers
    }
}

// ApiService
interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

// UserDao
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    suspend fun getAllUsers(): List<User>
    
    @Insert
    suspend fun insertAll(users: List<User>)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 3. 创建ViewModel

@HiltViewModel
class UserListViewModel @ViewModelInject constructor(
    private val repository: UserRepository
) : ViewModel() {
    
    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> = _users
    
    fun loadUsers() {
        viewModelScope.launch {
            _users.value = repository.getUsers()
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 4. 创建UI层

@AndroidEntryPoint
class UserListActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityUserListBinding
    private val viewModel: UserListViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityUserListBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        setupRecyclerView()
        observeViewModel()
        
        binding.refreshLayout.setOnRefreshListener {
            viewModel.loadUsers()
        }
    }
    
    private fun setupRecyclerView() {
        binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(this@UserListActivity)
            adapter = UserAdapter()
        }
    }
    
    private fun observeViewModel() {
        viewModel.users.observe(this) { users ->
            (binding.recyclerView.adapter as UserAdapter).submitList(users)
            binding.refreshLayout.isRefreshing = false
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 5. 配置Hilt Modules

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://jsonplaceholder.typicode.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

@Module
@InstallIn(SingletonComponent::class)
abstract class DatabaseModule {
    
    @Provides
    @Singleton
    fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "app_database"
        ).build()
    }
    
    @Provides
    fun provideUserDao(database: AppDatabase): UserDao {
        return database.userDao()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# Dagger迁移到Hilt的最佳实践

如果你已经在项目中使用Dagger并计划迁移到Hilt,以下是一些最佳实践:

# 1. 逐步迁移

不要一次性迁移整个项目,而是按模块或功能逐步迁移:

  1. 先在Application类中添加@HiltAndroidApp
  2. 逐步将Android组件迁移到@AndroidEntryPoint
  3. 将Dagger Module转换为Hilt Module
  4. 利用Hilt的预定义绑定简化代码

# 2. 保留Dagger组件

在迁移过程中,可以保留Dagger组件作为桥梁:

@Module
@InstallIn(ApplicationComponent::class)
object DaggerBridgeModule {
    
    @Provides
    @Singleton
    fun provideLegacyDaggerComponent(): LegacyDaggerComponent {
        return DaggerLegacyDaggerComponent.create()
    }
}
1
2
3
4
5
6
7
8
9
10

# 3. 利用Hilt的测试支持

Hilt提供了优秀的测试支持:

@RunWith(AndroidJUnit4::class)
class UserViewModelTest {
    
    @get:Rule
    var hiltRule = HiltAndroidRule(this)
    
    @Inject
    lateinit var repository: TestRepository
    
    @Before
    fun setup() {
        hiltRule.inject()
    }
    
    @Test
    fun getUsers_whenRepositoryReturnsUsers_updatesUiState() = runTest {
        // 测试代码
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 结语

从Dagger到Hilt,我们看到依赖注入框架在Android开发中的进化之路。Hilt不仅保留了Dagger的强大功能,还针对Android开发场景进行了深度优化,大大简化了依赖注入的使用。

"代码应该是简单的,而不是复杂的。依赖注入帮助我们实现这一点。"

在现代Android开发中,掌握Hilt已经不再是加分项,而是必备技能。它帮助我们构建更加模块化、可测试和可维护的应用程序。

如果你还没有开始使用Hilt,我强烈建议你从今天就开始尝试。相信我,一旦你习惯了这种开发方式,你将再也回不去没有依赖注入的日子!😉

最后,记住:依赖注入不是银弹,它只是帮助我们写出更好代码的工具。合理使用它,而不是滥用它,才能真正发挥它的价值。

希望这篇文章能帮助你更好地理解和使用Hilt。如果你有任何问题或建议,欢迎在评论区留言交流!👋

#依赖注入#Dagger#Hilt#Android架构
上次更新: 2026/01/28, 10:42:53
Android测试指南-从单元测试到UI测试的实践之路
Android网络编程完全指南-从HTTP到Retrofit的实践之路

← Android测试指南-从单元测试到UI测试的实践之路 Android网络编程完全指南-从HTTP到Retrofit的实践之路→

最近更新
01
LLM
01-30
02
intro
01-30
03
intro
01-30
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jorgen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式