Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Injecting view models into Composable functions with kotlin-inject

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
@humblehacker
Copy link
Author

humblehacker commented Mar 16, 2022

This write-up is the result of this conversation on the kotlinlang #kotlin-inject Slack channel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment