はじめに
巷で噂のDagger Hiltをようやく触ってみました。Codelabを一通り終わったので、実際に過去の記事でDaggerを使ってDIしたのですがそれをHiltに移行した手順をまとめます。
Gradle
// build.gradle (Project)
ext.hilt_version = '2.28-alpha'
dependencies {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
}
// build.gradle (App)
// Dagger_hilt
implementation "com.google.dagger:hilt-android:$hilt_version" // 必須
kapt "com.google.dagger:hilt-android-compiler:$hilt_version" // 必須
def dagger_hilt_view_model_version = "1.0.0-alpha01"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:${dagger_hilt_view_model_version}"
kapt "androidx.hilt:hilt-compiler:${dagger_hilt_view_model_version}"
今回は、ViewModelを使うので、hilt-compiler
とhilt-lifecycle-viewmodel
を追加した。
実装
移行の順番は、
- Application & @Singleton
- Fragment & Activity
ということで、Applicationを見てみましょう。
Application
Hiltに移行する前のコードがこちらです。Application
では、独自に設計したComponent
をインスタンス化していました。しかし、Hiltでは標準のComponentが用意されていてComponentを定義する必要がなくなったらしい。
class TodoApplication : Application() {
companion object {
lateinit var component: AppComponent private set
}
override fun onCreate() {
super.onCreate()
component = DaggerAppComponent.factory().create(applicationContext)
}
}
HiltではApplication
を@HiltAndroidApp
アノテーションをつけて定義します。
@HiltAndroidApp
class TodoApplication : Application() {
// companion object {
// lateinit var component: AppComponent private set
// }
//
// override fun onCreate() {
// super.onCreate()
// component = DaggerAppComponent.factory().create(applicationContext)
// }
}
このコードからわかるようにComponent
自体もいらないので、AppComponent
を削除します。
//@Singleton
//@Component(
// modules = [
// DatabaseModule::class
// ]
//)
//interface AppComponent {
//
// @Component.Factory
// interface Factory {
// fun create(@BindsInstance context: Context): AppComponent
// }
// fun mainViewModel(): MainViewModel
//}
Activity
元々あったComponent
を削除したので、ActivityやFragmentにInjectできるように、@AndroidEntryPoint
アノテーションを記述しなければならない。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
今回は、Fragmentが登場しませんが、もしFragmentにInjectしたいときはそれを所持するActivityにも@AndroidEntryPoint
を付ける必要があります。
Module
Moduleの定義方法は、@InstallIn(ApplicationComponent::class)
アノテーションをつける必要があります。@InstallIn
アノテーションでHiltが生成するComponentにModuleを紐付けます。
@InstallIn(ApplicationComponent::class)
@Module
class DatabaseModule() {
@Singleton
@Provides
fun provideTodoDatabase(@ApplicationContext context: Context) =
Room.databaseBuilder(context,
TodoDatabase::class.java,
"database_name")
.build()
@Singleton
@Provides
fun provideTodoDao(todoDatabase: TodoDatabase) = todoDatabase.todoDao()
}
移行前は、Context
をComponentのインスタンス生成する時に渡していたがそれをする必要がなくなりました。 すでにBinding済みのContextを使用することができます。@ApplicationContext
か@ActivityContext
をつけるだけで使用できます。
ViewModel
ViewModelをHiltを使ってDIする場合、constructorに@ViewModelInject
アノテーションをつけます。
class MainViewModel @ViewModelInject constructor(private val repository: TodoRepository) : ViewModel() {
最後Activityに、
private val mainViewModel: MainViewModel by viewModels()
を記述すれば移行完了です。