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-inject
Slack channel.