Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
    

}
like image 272
Karim Sinouh Avatar asked Apr 20 '21 13:04

Karim Sinouh


People also ask

How do you inject a ViewModel in hilt?

Inject ViewModel objects with HiltProvide a ViewModel by annotating it with @HiltViewModel and using the @Inject annotation in the ViewModel object's constructor. Note: To use Dagger's assisted injection with ViewModels, see the following Github issue.

How do I access ViewModel in composable?

If you use the Architecture Components ViewModel library, you can access a ViewModel from any composable by calling the viewModel() function.

How do you get ViewModel in jetpack compose?

There are two ways to declare the data within a ViewModel so that it is observable. One option is to use the Compose state mechanism which has been used extensively throughout this book. An alternative approach is to use the Jetpack LiveData component, a topic that will be covered later in this chapter.

Should I pass ViewModel to composable?

We recommend screen-level composables use ViewModel instances for providing access to business logic and being the source of truth for their UI state. You should not pass ViewModel instances down to other composables.


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
}
like image 108
Sepehr Avatar answered Oct 23 '22 15:10

Sepehr


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)
like image 31
Francesc Avatar answered Oct 23 '22 16:10

Francesc


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.
like image 25
Jatin Sachdeva Avatar answered Oct 23 '22 16:10

Jatin Sachdeva


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.

like image 38
OtienoSamwel Avatar answered Oct 23 '22 16:10

OtienoSamwel