According to the docs, the non-DI way to associate an view model with an @Composable is via the viewModel() function from androidx.lifecycle.viewmodel.compose.viewModel, like this:
@Composable
fun ProfileScreen(val viewModel: ProfileViewModel = viewModel() {
...But if your view model requires dependencies, you have to pass a subclass of ViewModelProvider.Factory that holds the dependency and knows how to construct the view model for you. Like this:
class ProfileViewModelFactory(private val userRepository: UserRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass
.getConstructor(UserRepository::class.java)
.newInstance(userRepository)
}
}Then you'd have to pass the factory to your @Composable instead of the view model. Like this:
@Composable
fun ProfileScreen(vmFactory: ProfileViewModelFactory) {
val viewModel: ProfileViewModel = viewModel(factory = vmFactory)
...So injection becomes a simple matter of annotating the above function and ProfileViewModelFactory:
@Inject
@Composable
fun ProfileScreen(vmFactory: ProfileViewModelFactory) {
val viewModel: ProfileViewModel = viewModel(factory = vmFactory)
...
@Inject
class ProfileViewModelFactory(private val userRepository: UserRepository) : ViewModelProvider.Factory {
...… and configuring it in your component:
@Component
abstract class AppComponent() {
abstract val ProfileScreen: ProfileScreen
This write-up is the result of this conversation on the kotlinlang
#kotlin-injectSlack channel.