Android Hilt 入门教程_传统写法和Hilt写法的比较

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

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

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


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

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

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

问题

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

✅ 使用 Hilt 进行解耦

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

Hilt 提供的 ApiService 实例

kotlin 复制代码
@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    @Singleton
    fun provideApiService(): ApiService {
        return RealApiService()
    }
}

解耦优势

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

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

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

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

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

问题

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

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

🛠️ 在测试中提供 FakeApiService

kotlin 复制代码
@HiltAndroidTest
@UninstallModules(AppModule::class) // 先卸载正式模块
class MyRepositoryTest {

    @Module
    @InstallIn(SingletonComponent::class)
    object TestModule {
        @Provides
        fun provideFakeApiService(): ApiService {
            return object : ApiService {
                override fun getData(): String {
                    return "Fake Data"
                }
            }
        }
    }

    @Inject
    lateinit var repository: MyRepository

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @Before
    fun setup() {
        hiltRule.inject()  // 让 Hilt 注入测试依赖
    }

    @Test
    fun 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 的情况下,我们通常需要手动创建对象:

kotlin 复制代码
class MyRepository {
    private val apiService = ApiService()  // 直接创建实例
}

问题

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

Hilt 作为对象工厂

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

kotlin 复制代码
class MyRepository @Inject constructor(private val apiService: ApiService) { }

Hilt 自动提供 ApiService 实例

kotlin 复制代码
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    @Singleton
    fun 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 关闭时释放)

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

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

问题

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

Hilt 自动管理生命周期

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

🎯 Application 作用域(全局单例)

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

🎯 Activity 作用域(Activity 级别)

kotlin 复制代码
@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

kotlin 复制代码
@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 自动匹配对象生命周期
测试支持 需要大量 Mock Hilt 允许轻松替换依赖

💡 总结

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

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

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

相关推荐
wuwu_q2 小时前
用通俗易懂方式,详细讲讲 Kotlin Flow 中的 map 操作符
android·开发语言·kotlin
_李小白2 小时前
【Android FrameWork】第五天:init加载RC文件
android
2501_916007473 小时前
手机使用过的痕迹能查到吗?完整查询指南与步骤
android·ios·智能手机·小程序·uni-app·iphone·webview
黄毛火烧雪下3 小时前
React Native (RN)项目在web、Android和IOS上运行
android·前端·react native
下位子4 小时前
『OpenGL学习滤镜相机』- Day7: FBO(帧缓冲对象)
android·opengl
從南走到北4 小时前
JAVA国际版同城外卖跑腿团购到店跑腿多合一APP系统源码支持Android+IOS+H5
android·java·ios·微信小程序·小程序
空白格974 小时前
组件化攻略
android
岸芷漫步4 小时前
android框架层弹出对话框的分析
android
Android疑难杂症4 小时前
鸿蒙Media Kit媒体服务开发快速指南
android·harmonyos·音视频开发