Androidアプリでヒルトを実行する方法?


依存インジェクションライブラリを使用するのは難しいですが、この記事は、シンプルで簡単にあなたのAndroidアプリでヒルトを実装する手順に従って提供します.
この記事はもともと1967年に出版されましたvtsen.hashnode.dev 2022年2月5日

導入
依存性注入の3種類があります.

  • Manual dependency injection - コンストラクタパラメータによる依存関係の注入

  • Service locator - 依存関係を保持するSingletonコンテナ

  • 依存性注入ライブラリHilt/Dagger また、Koinはコード依存のマニュアル依存注入と同様の機能を提供します.
  • 依存性の注入ライブラリを使用するのは難しいです.私が最初にヒルト/ダガーとKoinについて聞いたとき、私は彼らが何であるか全くわからなかったです.それで、私は彼らの文書とチュートリアルを読みます、それは私の理解さえ最悪にします!
    私の最初の経験はKoinAndroid Kotlin Developer Nonodegree program . コードはすでに提供され、私は100 %それを理解せずに使用します.
    Koinを理解しようとするのではなく、私は短剣の上に構築されたヒルトに遭遇し、それはユーザーフレンドリーであると仮定します.それで、私はこれを試してみました、そして、私はこの便利で単純な公式チュートリアルを見つけましたUsing Hilt in your Android app . このチュートリアルでは、サービスのロケータをhilt依存性注入に変換する手順を示します.
    それで、Hiltを実行する手順を文書化するのは良い考えだと思います.このチュートリアルでは、このチュートリアルの手順をまとめます.

    1 .セットアップの依存
    インbuild.gradle (プロジェクトレベル)、ヒルトAndroid Gradleプラグインを追加します.
    buildscript {
        ...
        }
        dependencies {
            ...
            classpath 'com.google.dagger:hilt-android-gradle-plugin:2.40'
        }
    }
    
    
    インbuild.gradle (アプリケーションレベル)kotlin-kapt and dagger.hilt.android.plugin .
    plugins {
        ...
        id 'kotlin-kapt'
        id 'dagger.hilt.android.plugin'
    }
    
    
    ヒルト実装依存を追加します.
    dependencies {
        ...
        implementation 'com.google.dagger:hilt-android:2.40'
        kapt 'com.google.dagger:hilt-android-compiler:2.40'
       ...
    }
    

    追加@HiltAndroidApp アプリケーションクラスで
    アプリケーションクラスがない場合は、1つを作成する必要があります.
    @HiltAndroidApp
    class LogApplication : Application() {
        ...
    }
    
    また、更新する必要がありますandroid:nameAndroidManifest.xml .
    <manifest>
    
        <application
            android:name=".LogApplication"
            ...
        </application>
    </manifest>
    

    追加@AndroidEntryPoint あなたの活動と断片で
    あなたの依存関係をアクティブに注入する場合は、追加する必要があります@AndroidEntryPoint あなたの活動クラスで.ただし、あなたの依存関係をフラグメントに注入する場合は、@AndroidEntryPoint フラグメントをホストする両方のフラグメントとアクティビティー.
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
        ...
    }
    
    @AndroidEntryPoint
    class LogsFragment : Fragment() {
        ...
    }
    

    追加@Inject lateinit var フィールド注入を行う
    用途@Inject lateinit var クラスのフィールドでHiltを自動的にインスタンスを作成します.この例では、ヒルトは自動的にlogger 断片が最初に付けられた後のあなたのためのインスタンスonAttach() がコールされます)
    class LogsFragment : Fragment() {
        ...
        @Inject lateinit var dateFormatter: DateFormatter
        @Inject lateinit var logger: LoggerDataSource
    
        ...
    }
    

    追加@Inject constructor() Hiltに依存関係を提供する方法
    Hiltはどのように作成するかわからないDateFomatter and LoggerDataSource . そのためには、@Inject constructor() クラスに.
    //Hilt knows how DataFormatter can be constructor injected
    class DateFormatter @Inject constructor() {
        ...
    }
    
    //Hilt still doesn't know how LoggerLocalDataSource can be constructor injected 
    class LoggerLocalDataSource @Inject constructor(private val logDao: LogDao) {
        ...
    }
    
    行方不明の情報のためにLogDao , Hiltはまだコンストラクタに注入する方法を知らないLoggerLocalDataSource . したがって、我々はcreate the hilt module 言うLogDao を作成できます.

    6追加@Singleton アプリケーション全体へのスコープのスコープ
    @Singleton
    class LoggerLocalDataSource @Inject constructor(private val logDao: LogDao) : LoggerDataSource {
        ...
    }
    
    これはLoggerLocalDataSource アプリケーション全体に使用されます.違うcomponent scopes 例えば@ActivityScoped , FragmentScoped and @ViewModelScoped .

    追加@Module and @InstallIn ヒルトモジュールを作成するには
    これらのクラスでは、依存関係をインクルードする方法を知らないクラスでは、ヒルトモジュールを作成する必要があります.
    @InstallIn(SingletonComponent::class)
    @Module
    object DatabaseModule {
        ...
    }
    
    @InstallIn コンポーネントのスコープに関連するモジュールをインストールする必要があります.

    インスタンスを注入する@Providesが2です@Provides . 第一@Provides 情報を提供する方法LogDao を作成できます.それは依存するからAppDatabase , 二番目@Provides 情報提供AppDatabase を作成できます.
    @InstallIn(SingletonComponent::class)
    @Module
    object DatabaseModule {
    
        @Provides
        fun provideLogDao(database: AppDatabase): LogDao {
            return database.logDao()
        }
    
        @Provides
        fun provideDatabase(@ApplicationContext appContext: Context): AppDatabase {
            return Room.databaseBuilder(
                appContext,
                AppDatabase::class.java,
                "logging.db"
            ).build()
        }
    }
    
    注意してください@ApplicationContext ヒルトを自動的に取得することを意味定義済みのバインドですApplicationContext あなたに.

    インタフェースインスタンスを注入する@Binds注入されたフィールドがインターフェースであるならば、あなたはインターフェースのインプリメンテーションを提供する方法をHiltに教える必要があります@Binds .
    @InstallIn(ActivityComponent::class)
    @Module
    abstract class NavigationModule {
    
        @Binds
        abstract fun bindNavigator(impl: AppNavigatorImpl): AppNavigator
    }
    
    抽象関数とクラスが必要であることに注意してください@Binds .

    追加@Qualifier 同じインターフェースを持つ2つの実装
    フィールドインジェクションがインターフェイスで、複数の実装がある場合は、@Qualifier Hiltを区別する方法を教えてください.

    たとえば、追加する必要があります@Qualifier for LoggerLocalDataSource and LoggerInMemoryDataSource.定義する@Qualifier ヒルトモジュールのクラスで、LoggerLocalDataSource and LoggerInMemoryDataSource.
    @Qualifier
    annotation class InMemoryLogger
    
    @Qualifier
    annotation class DatabaseLogger
    
    追加@DataBaseLogger and @InMemoryLogger 以上の修飾子Binds .
    @InstallIn(SingletonComponent::class)
    @Module
    abstract class LoggingDatabaseModule {
    
        @DatabaseLogger
        @Binds
        abstract fun bindDatabaseLogger(impl: LoggerLocalDataSource): LoggerDataSource
    }
    
    @InstallIn(ActivityComponent::class)
    @Module
    abstract class LoggingInMemoryModule {
    
        @InMemoryLogger
        @Binds
        abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource): LoggerDataSource
    }
    
    フィールドインジェクション変数の上に修飾子を追加し、使用する実装を示します.例えば、@DatabaseLogger 指示LoggerLocalDataSource 実装が使用されます.
    @DatabaseLogger
    @Inject lateinit var logger: LoggerDataSource
    

    結論
    正直なところ、依存関係インジェクションライブラリのファンではありません.それはコードを理解するのが難しくなります.コンパイルエラーがあるなら、修正するのは難しいです.少なくとも私にとって、それは難しいです.今のところ、それは私の生産性を改善しないが、他の方法ラウンド.
    一方、サービスロケータは、依存関係を注入しないので、技術的に依存性の注入ではありません.これは、消費者はどこからでも依存関係を取得することができます.それは基本的にグローバルなオブジェクトです.
    すべてのこれらの理由を考えて、私はまだ手動またはコンストラクタ依存性注入を使用する方が好きです.これは、明確で、簡単にデバッグしやすいです.誰でもあなたのコードを理解できます.これではないclean code アバウト?
    私は依存関係の注入をマスターしていないので、私はこれを言う知っている.いつの日か私は望みます.

    参考
  • Android Development Tips and Tricks