How to inject a ViewModel into a composable function using Hilt (Jetpack Compose)

Viewed 12746

I'm doing the same as shown in the documentation here. I want to Inject the ViewModel into a Composable function (Screen), but I get this error:

Cannot create an instance of class com.example.blotube.ui.later.LaterViewModel

My ViewModel:

@HiltViewModel
class LaterViewModel @Inject constructor(
    private val database: Database
):ViewModel() {

    val watchLater=database.videos().getAll()

}

My Composable Function (Screen):

@Composable
fun WatchLater(vm: LaterViewModel = viewModel()){


    val videos=vm.watchLater.observeAsState()
    val context= LocalContext.current
    

}
4 Answers

From version androidx.hilt:hilt-navigation-compose:1.0.0-alpha02 you can inject view model into Composable functions by:

hiltViewModel<ViewModelType>()

Example:

@Composable 
fun LoginScreen(viewModel: LoginViewModel) {}

LoginScreen(
    viewModel = hiltViewModel<LoginViewModel>()
)

Android Developer Documentation compose and hilt

UPDATE:

import androidx.hilt.navigation.compose.hiltViewModel

@Composable 
fun LoginScreen(
    viewModel: LoginViewModel = hiltViewModel()
){
   val videos=vm.watchLater.observeAsState()
   val context= LocalContext.current
}

This appears to be a bug in Jetpack Compose, will probably need to wait for an update on the Jetpack libraries to address it.

As a possible workaround, you could instantiate the viewmodel in your activity and pass it to your composable function

val viewModel: LaterViewModel = viewModel(
    "later_viewmodel",
    factory = defaultViewModelProviderFactory
)
WatchLater(viewModel)

if you are using the Nav graph component you can also scope your viewmodel to the nav graph using

val viewModel: LaterViewModel = hiltNavGraphViewModel<LaterViewModel>()
WatchLater(viewModel)

You can use ViewModel directly inside Composable function via hiltViewModel()

@Composable
fun WatchLater(vm: LaterViewModel = hiltViewModel()) {

  val videos = vm.watchLater.observeAsState()
  val context = LocalContext.current

}

Please make sure to add following

  1. Adding androidx.hilt:hilt-navigation-compose dependency to your module level Gradle file. Do check for latest version(tested on 1.0.0-alpha03).
  2. @HiltViewModel to your ViewModel.
  3. @AndroidEntryPoint for the owner using the Composable function.

I find the simplest way to do it is inside your composable function. Add the dependency implementation 'androidx.hilt:hilt-navigation-compose:1.0.0' then;

@Composable 
fun Foo(){
    val viewModel : Bar = hiltViewModel()
}

then you can use the viewmodel as usual.

Related