
【Android Hilt 依賴注入完整教學】系列文章目錄:連結
Youtube 教學頻道:HKT線上教室
今天要跟大家分享的是如何在 Android 專案中使用 Hilt Modules。這是一個非常重要的主題,因為 Modules 是 Hilt 依賴注入框架中用於組織和提供依賴的核心機制。透過 Modules,我們可以更有效地管理複雜的依賴關係,提供介面的具體實作,以及控制物件的生命週期。本文將深入探討 Modules 的概念、使用時機與實作方式,幫助您更好地運用這個強大的功能。
Hilt Modules 是什麼?
Hilt Modules 本質上是一個類別,用於告訴 Hilt 框架如何建立和管理物件的生命週期。當我們需要注入的對象是介面(Interface)或是抽象類別時,Modules 就特別重要,因為 Hilt 需要知道具體要建立哪個實作類別。
Modules 在 Hilt 中扮演著以下重要角色:- 提供依賴的來源:
- 當無法直接使用建構子注入時(如第三方函式庫的類別)
- 需要在建立物件時進行額外設定
- 需要根據不同條件提供不同實作
- 管理物件生命週期:
- 可以指定物件的作用域(Scope)
- 控制物件是否為單例(Singleton)
- 決定物件的重用策略
- 模組化程式碼:
- 將相關的依賴設定集中管理
- 提高程式碼的可維護性
- 方便測試時替換實作
使用時機:
- 需要注入介面或抽象類別的實作
- 需要注入第三方函式庫的類別
- 需要在建立物件時進行複雜的初始化
- 需要根據不同環境(如測試/正式)提供不同實作
實作範例
讓我們透過一個實際的範例來了解:
// 定義一個介面
interface AlertSystem {
fun startAlerting()
}
// 實作介面
class NoiseAlertSystem(private val context: Context) : AlertSystem {
override fun startAlerting() {
println(context.getString(R.string.test_string))
}
}
// 建立 Module
@Module
@InstallIn(ActivityComponent::class)
object AlertSystemModule {
@Provides
fun provideAlertSystem(@ApplicationContext context: Context): AlertSystem {
return NoiseAlertSystem(context)
}
}
重要觀念說明
1. Module 的生命週期
使用 @InstallIn
註解來指定 Module 中提供的依賴項的生命週期範圍:
SingletonComponent
:整個應用程式生命週期- 適用於全域性的服務或工具類別
- 物件會在應用程式啟動時建立,直到應用程式結束才會銷毀
- 需要謹慎使用,因為會佔用記憶體直到應用程式結束
- 例如:資料庫實例、網路客戶端、共用偏好設定管理器
ActivityComponent
:Activity 生命週期- 每個 Activity 都會有自己的實例
- 物件會在 Activity 建立時產生,Activity 結束時銷毀
- 適用於與特定 Activity 相關的功能
- 例如:Activity 專用的 Presenter、特定畫面的資料管理器
ViewModelComponent
:ViewModel 生命週期- 跟隨 ViewModel 的生命週期
- 在螢幕旋轉等組態變更時會保持存活
- 適合處理 UI 相關的資料和邏輯
- 例如:表單資料暫存、畫面狀態管理
FragmentComponent
:Fragment 生命週期- 每個 Fragment 擁有獨立的實例
- 隨 Fragment 的建立和銷毀而生滅
- 適用於 Fragment 特定的功能需求
- 例如:Fragment 的視圖控制器、局部資料管理
注意事項:
- 選擇適當的 Component 對於記憶體管理和效能優化很重要
- 避免在較長生命週期的 Component 中持有較短生命週期的物件引用
- 需要考慮物件的狀態管理和資源釋放
2. 提供依賴的方法
在 Module 中,我們使用 @Provides
註解來標記提供依賴的方法。這個方法需要:
- 明確的回傳型別:
- 必須明確指定方法要提供的依賴類型
- 可以是具體類別或介面
- Hilt 會根據這個型別來解析依賴關係
- 同一個型別如果有多個提供者,需要使用限定符(Qualifier)區分
- 必要的參數(如果需要):
- 方法可以接受其他依賴作為參數
- 這些參數也必須能被 Hilt 提供
- 常見的參數包括:
- Context(需要適當的限定符)
- 其他被 @Inject 或 @Provides 標記的依賴
- 配置參數(如 API URL、資料庫名稱等)
- 方法命名建議:
- 使用 provide 作為前綴
- 清楚表達提供的依賴類型
- 如果同一型別有多個提供者,名稱要能區分用途
- 提供方法的特性:
- 必須是非抽象的具體方法
- 可以包含初始化邏輯
- 可以進行條件判斷
- 可以整合多個依賴
使用情境
Hilt Modules 特別適用於以下情況:
- 需要注入介面的實作
- 當您有一個介面和多個實作類別時
- 可以在 Module 中指定要使用哪個實作
- 例如:不同的資料來源介面(API、資料庫、快取)
- 方便在測試時替換成測試用的實作
- 需要注入第三方函式庫的類別
- 對於無法修改源碼的第三方元件
- 需要為第三方類別提供初始化設定
- 例如:Retrofit、Room Database、OkHttpClient
- 可以在 Module 中封裝所有相關設定
- 需要在建立物件時進行額外的設定
- 當物件需要複雜的初始化邏輯
- 需要多個參數或相依物件來建立實例
- 例如:設定 API 金鑰、資料庫連線參數
- 可以將初始化邏輯集中在一處管理
- 需要管理物件的生命週期
- 控制物件的作用域和存活時間
- 決定是否要重複使用相同實例
- 例如:單例模式的資料庫連線
- 可以使用作用域註解(@Singleton、@ActivityScoped 等)
- 需要條件式提供不同實作
- 根據執行環境選擇不同實作
- 依據使用者設定切換實作
- 例如:開發/正式環境的 API 端點
- 可以使用限定符(Qualifier)來區分
注意事項
- 確保
@InstallIn
使用正確的 Component: - SingletonComponent:應用程式級別的依賴
- ActivityComponent:Activity 範圍的依賴
- FragmentComponent:Fragment 範圍的依賴
- ViewComponent:View 範圍的依賴
- ServiceComponent:Service 範圍的依賴
- 使用錯誤的 Component 可能導致生命週期問題
- 留意依賴的生命週期管理:
- 使用適當的作用域註解(@Singleton、@ActivityScoped 等)
- 避免將短生命週期的物件注入到長生命週期的物件中
- 注意記憶體洩漏的可能性
- 定期使用工具(如 LeakCanary)檢查記憶體洩漏
- 如果遇到錯誤,仔細檢查錯誤訊息,找出依賴鏈中的問題:
- 常見錯誤類型:
- 循環依賴(Circular dependency)
- 缺少必要的依賴提供者
- Component 層級不匹配
- 作用域衝突
- 解決方法:
- 使用 Hilt 的除錯工具查看依賴圖
- 檢查所有相關類別的註解是否正確
- 確認所有依賴都有對應的提供者
- 考慮重構依賴結構
- 模組設計建議:
- 依功能或層級分割模組
- 避免過大的模組
- 確保模組之間的相依性清晰
- 適當使用抽象化來增加彈性
- 效能考量:
- 避免在 Module 中進行耗時操作
- 合理使用作用域來重用物件
- 注意記憶體使用量
- 考慮使用延遲初始化(Lazy Injection)
下一步
在下一篇文章中,我們將探討如何在同一個介面提供多個實作,這在需要根據不同情境使用不同實作時特別有用。