手動でDIを実現する方法 + Daggerを取り除く
Dagger-Hiltを使えば、viewModule()
関数で任意のViewModel
インスタンスを生成・取得できますが、次の動画では、ViewModelProvider.Factory
を使って手動で生成・取得を実現する方法を紹介しています。
YouTube - Full Guide to Manual Dependency Injection + Removing Dagger |
Dagger-Hiltを使ったDIの例(元となるソースコード)
手動でDIを実現する方法(変更されたソースコード)
構造
AndroidManifest
applicationにMyApp
クラスを、activityにMainActivity
クラスを指定しています。
<application android:name=".MyApp" ... >
<activity android:name=".MainActivity" ... >
...
</activity>
</application>
クラス図
Application
、ComponentActivity
、ViewModel
、AuthRepository
に関するクラスを次のクラス図に示します。
ViewModelの生成と取得
ViewModelProvider.Factory
を使って、任意の引数付きのViewModelを生成・取得します。
Factoryヘルパー関数
動画では、汎用的なヘルパー関数であるviewModelFactory
関数が紹介されています。
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
fun <VM: ViewModel> viewModelFactory(initializer: () -> VM): ViewModelProvider.Factory {
return object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return initializer() as T
}
}
}
MainViewModelの生成と取得
viewModel
関数とFactoryヘルパー関数とを使って、次のようにMainViewModel
インスタンスを生成・取得できます。
:
import androidx.lifecycle.viewmodel.compose.viewModel
import com.plcoding.manualdependencyinjection.presentation.MainViewModel
import com.plcoding.manualdependencyinjection.presentation.viewModelFactory
:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ManualDependencyInjectionTheme {
val viewModel = viewModel<MainViewModel>(
factory = viewModelFactory {
MainViewModel(MyApp.appModule.authRepository)
}
)
:
}
}
}
}
まとめ
動画で紹介されたviewModelFactory
ヘルパー関数を使って、任意の引数があるViewModel
クラスのインスタンスをviewModel
関数を用いて、生成・取得ができることを学びました。
補足 - ViewModelProvider.Factoryは不要
動画では、ViewModelProvider.Factory
を用いていますが、現在では、その必要はありません。
June 29, 2022
androidx.lifecycle:lifecycle-*:2.5.0 is released.
lifecycle-viewmodel-compose
now offers aviewModel()
API that takes a lambda factory for creating aViewModel
instance without requiring the creation of a customViewModelProvider.Factory
.
// Within a @Composable, you can now skip writing a custom Factory
// and instead write a lambda to do the initialization of your ViewModel
val detailViewModel = viewModel {
// This lambda is only called the first time the ViewModel is created
// and all CreationExtras are available inside the lambda
val savedStateHandle = createSavedStateHandle()
DetailViewModel(savedStateHandle)
}
よって、MainViewModelを生成・取得するには、次のコードで実現できます。
val viewModel = viewModel {
MainViewModel(MyApp.appModule.authRepository)
}