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

5

47

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
    

}
Twelve answered 20/4, 2021 at 13:34 Comment(0)
L
61

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
}
Legendary answered 11/6, 2021 at 21:5 Comment(7)
Simply use inside compose exampleViewModel: ExampleViewModel = viewModel()Cyclostyle
seems hiltViewModel() isn't available anymoreLinesman
Following your setup I got the following error: CreationExtras must have a value by SAVED_STATE_REGISTRY_OWNER_KEYAllophone
Can you provide an example with @AssistedInject?Swob
check this @Swob medium.com/scalereal/…Och
I tried doing this but the init function of the viewmodel is never called. Did someone else get this issue?Dayflower
can we pass custom args in viewModel init like this?Tennies
C
10

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.

Candide answered 27/1, 2022 at 8:55 Comment(0)
B
9

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.
Badoglio answered 14/11, 2021 at 13:35 Comment(1)
I am getting hiltViewModel() as an unresolved referenceKaddish
M
6

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)
Monica answered 20/4, 2021 at 16:10 Comment(1)
Thank you so much, I think scoping the view model to the nav graph is my best solution for now.Twelve
T
3

base document Inject Hilt In Composable Function

Note: notice to import class

Sample you can used viewModel()

Example:

...
import androidx.lifecycle.viewmodel.compose.viewModel
...
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

Full Example:

...
import androidx.lifecycle.viewmodel.compose.viewModel
...
@HiltViewModel
class MyViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) { /* ... */ }
Toombs answered 2/1, 2023 at 20:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.