Android-Dagger. 使 專案 專案 好 , , 限制 性 , 優化 專案 , 也 適用 重構 重構 專案 | de miles | Octubre de 2020

整個 整個 專案 好 維護 , 限制 複雜 性 , 優化 專案 , 也 於 於 重構 專案

注解 注解

@Inject , 標記 物件 需要 注入 依賴 的 對象 , ý ka ka 獲取 獲取 所需 的 參數 值 並 調用 此 構造 函數 , 以下 範例。

class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) { ... }
@Inject
lateinit var mainViewModel: MainViewModel

注意 @Inject 用 用 private

@Componente會讓 定義 返回 需要 函數 , 會讓 ý ka ka 一個 一個 , 其中 其中 包含 滿足 滿足 其 的 類型 類型 的 所有 依賴 項 ,是 必須 是 interfaceabstract下 範例。

@Component
interface ApplicationGraph {
fun repository(): UserRepository
}

@Módulo 告知 告知 ý ka ka 提供 類 類 , 以下 以下 範例。

@Module
class NetworkModule {
@Provides
fun provideLoginRetrofitService(): LoginRetrofitService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(LoginService::class.java)
}
}

@Proporciona 告知 定義 依賴 項 , 告知 ý ka ka 提供 您 您 項目 項目 所 不 具備 的 類 (, Retrofit , 實例)。

@Enlaza 告訴 Daga 告訴 接口 時 需要 使用 哪種 實現。

@Singleton 可以 可以 被 多個 線程 共享。

@BindsInstance告訴 Daga 告訴 它 需要 在 圖形 中 添加 該 實例 , 並 在Context時 時 提供 該 實例。

@Subcomponent告訴 接口 告訴 Daga ý 是 一個 子 組件。

Android 使用

app / build.gradle 範例 以下 範例 , 也 可以 參考 最新 的Daga

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
... dependencies {
...
def dagger_version = "2.27"
implementation "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"
}

導入 專案 導入 Daga

舉例 ViewModel 需要 加上 @Inject 表示 表示 Dagger 依賴 依賴 , 如果 是 構造 函數 必須 加上 constructor以下 以下 範例。

class RegistrationViewModel @Inject constructor(val userManager: UserManager) {
...
}

Actividad 實現

將 已經 的 將 ViewModel 的 依賴 , 所以 在 原有 的 Activity 刪除 刪除 onCreate 中 ViewModel 的 實例 , 以下 範例。

class RegistrationActivity : AppCompatActivity() {

@Inject
lateinit var registrationViewModel: RegistrationViewModel

override fun onCreate(savedInstanceState: Bundle?) {
registrationComponent =
(application as MyApplication).appComponent.registrationComponent().create()

// 刪除的實例
// registrationViewModel = RegistrationViewModel((application // as MyApplication).userManager)
}
}

Daga 創建 項目 管理

Com 需要 創建 一個 能 管理 互相 依賴 的 關係 , 使用 @Component , 建立 一個 interface 以下 以下 範例。

@Component
interface AppComponent {
fun inject(activity: RegistrationActivity)
}

來 一 來 Actividad 就 可以 透過 @Component 跟 跟 ViewModel 互相 依賴。

Módulo de daga

讓 讓 interfaz 實例 化 , 以下 範例。

interface Storage {
fun setString(key: String, value: String)
fun getString(key: String): String
}

當 Almacenamiento 為 Interfaz 要 在 Dagger 實現 SharedPreferencesStorage。

class SharedPreferencesStorage @Inject constructor(context: Context) : Storage {

private val sharedPreferences = context.getSharedPreferences("Dagger", Context.MODE_PRIVATE)

override fun setString(key: String, value: String) {
with(sharedPreferences.edit()) {
putString(key, value)
apply()
}
}

override fun getString(key: String): String {
return sharedPreferences.getString(key, "")!!
}
}

使用 使用@Module 創建 創建 clase StorageModule

@Module
abstract class StorageModule {
@Binds
abstract fun provideStorage(storage: SharedPreferencesStorage): Storage
}

@Binds註釋 註釋 一個 抽象 函數。

  • provideStorageÝ 一個 任意 的 方法 名稱 , 它 可以 是 我們 喜歡 的 任何 東西 , 對 ý ka 無關緊要 無關緊要 無關緊要 ý ka ka 關心 關心 是 參數 和 返回 類型。
  • StorageModuleabstract因為 因為provideStorage抽象 抽象 的。

得 原本 得 AppComponent 剛剛 剛剛 寫 的StorageModule

@Component(modules = [StorageModule::class])
interface AppComponent {

fun inject(activity: RegistrationActivity)
}

程序 定義 應用 程序

創建 MyApplication.kt 應用 應用 程序 運行 期間 一直 處於 內存 中 , 這樣 便會 附加 到 應用 程序 的 生命 週期 中 , 範例 範例。

open class MyApplication : Application() {
val appComponent: AppComponent by lazy {
DaggerAppComponent.factory().create(applicationContext)
}
}

範圍 範圍

在 在 Componente 中 提供 相同 的 依賴 項 實例 , 共用 同 一個 , 不需要 一直 創建 新 的 , Dagger 提供類型 類型 的 範圍 限定 為 組件 的 生命 週期 , 以下 範例

@Singleton
@Component(modules = [StorageModule::class])
interface AppComponent { ... }

可以 可以 注釋 實例 , 以下 範例。

@Singleton
class UserManager @Inject constructor(private val storage: Storage) {
...
}

告訴 Daga 提供 提供Context

Fábrica 使用 的 方法 是 使用 Fábrica de componentes 使用 使用@BindsInstance註釋以下 以下 範例。

@Singleton
@Component(modules = [StorageModule::class, AppSubcomponents::class])
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}

fun userManager(): UserManager
fun registrationComponent(): RegistrationComponent.Factory
fun loginComponent(): LoginComponent.Factory
}

Fragmento 添加 Daga

跟 Actividad 不同 ,onAttach注入 調用 之後 使用 方法 注入 Componentes super.onAttach以下 範例。

class EnterDetailsFragment : Fragment() {

override fun onAttach(context: Context) {
super.onAttach(context)

(requireActivity().application as MyApplication).appComponent.inject(this)
}
}

  • onCreate調用 調用 super 之前 , actividad 會 在 方法 中 註入 daga。
  • onAttach調用 調用 super 一個 , 一個 Fragmento 在 方法 中 註入 ý Dagger。

Subcomponentes de daga (組件 組件)

組件 組件 是 繼承 並 擴展 父 組件 的 對 圖 的 , 因此 因此 , 父 對 提供 對 對 對 像 在 在。 提供 提供。 中 中 中 的 父 父 父 父 父 父 提供 提供

創建 RegistrationComponent.kt 創建 以下 範例。

@Subcomponent
interface RegistrationComponent {

}

將 將 特定 類型 的 信息 都 放在 一起 ,AppComponent其 中 公開 其 Fábrica。 以下 範例。

@Subcomponent
interface RegistrationComponent {

@Subcomponent.Factory
interface Factory {
fun create(): RegistrationComponent
}

// 特定類型
fun inject(activity: RegistrationActivity)
fun inject(fragment: EnterDetailsFragment)
fun inject(fragment: TermsAndConditionsFragment)
}

讓 讓AppComponent知道RegistrationComponent建立 它 的 子 , , 需 建立 AppSubcomponents.kt , 以下 範例。

@Module(subcomponents = [RegistrationComponent::class])
class AppSubcomponents

AppComponent.kt 寫入 裡 寫入 AppSubcomponents , 以下 範例。

@Singleton
@Component(modules = [StorageModule::class, AppSubcomponents::class])
interface AppComponent { ... }

組件 界定 子 組件

一個 一個 子 組件 是 因為 我們 需要ViewModel在 Actividad 和 Fragmentos 之間 共享 相同 的 實例。 如果 我們 使用 相同 的 作用域 註釋 對 Carpeta 和 類 進行 進行 註釋 , 將使 該 類型 在 Carpeta 中 具有 唯一 的 實例 , 但是 , 我們 無法 使用 ,@Singleton因為AppComponentS 這種 情況 下 範圍 範圍。 需要 創建 另一個。 創建 ActivityScope.kt , 在 想要 的 範圍 裡 註解 , 以下 。。

@Scope
@MustBeDocumented
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ActivityScope

在 在 想要 的 範圍 註解 , 以下 範例。

@ActivityScope
class RegistrationViewModel @Inject constructor(val userManager: UserManager) {
...
}

週期 組件 生命 週期

Actividad 就像 保留 對 組件 的 引用 , 就像appComponent在 Aplicación 類 中 保留 對 組件 的 引用 一樣。 這樣 , 片段 將 能夠 訪問 它 , 以下 範例。

class RegistrationActivity : AppCompatActivity() {

lateinit var registrationComponent: RegistrationComponent
...
}

class RegistrationActivity : AppCompatActivity() {

lateinit var registrationComponent: RegistrationComponent

@Inject
lateinit var registrationViewModel: RegistrationViewModel

override fun onCreate(savedInstanceState: Bundle?) {
registrationComponent =
(application as MyApplication).appComponent.registrationComponent().create()
registrationComponent.inject(this)

super.onCreate(savedInstanceState)
}

registrationComponent對其 對其 進行 註釋 ,@Inject希望 我們 不 希望 ý ka 提供 提供 變量。

參考資料

https://codelabs.developers.google.com/codelabs/android-dagger/index.html?index=..%2F..index#4

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *