How to pass id and application to a viewModel/viewModelFactory in Jetpack Compose?

Viewed 4086

I use Jetpack Compose and navigation compose and I want to pass id to this viewmodel:

class RecallViewModel(private val id:Long,application: Application):AndroidViewModel(application) {
  ............................
}

Composable function:

I don't know how to get the application in composable function:

@Composable
fun RecallScreen(
    id:Long,
    onEnd:() -> Unit
){
       val recallViewModel = viewModel(factory = RecallViewModelFactory(
id = id,application = "i don't know how to get application"))

}

and factory

class RecallViewModelFactory(private val id:Long,val application: Application):ViewModelProvider.AndroidViewModelFactory(application) {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return RecallViewModel(id,application) as T
    }
}

        composable(
            "${Routes.recall}/{id}",
            arguments = listOf(navArgument("id") { type = NavType.LongType })
        ) {
            RecallScreen(
                id = it.arguments!!.getLong("id"),
                onEnd = {navController.navigateUp()}
            )
        }

1 Answers

To answer your question: you retrieve the Application from the LocalContext object:

val context = LocalContext.current
val application = context.applicationContext as Application

However, when using Navigation Compose, you don't need to manually pass any arguments to your ViewModel. Instead, you can utilize the built in support for SavedState in ViewModels and add a SavedStateHandle parameter to your ViewModel. The SavedStateHandle is a key/value map that is automatically populated with the arguments of your destination.

This means your ViewModel becomes:

class RecallViewModel(
    application: Application,
    savedStateHandle: SavedStateHandle
):AndroidViewModel(application) {

  // Get your argument from the SavedStateHandle
  private val id: Long = savedStateHandle.get("id")

  ............................
}

And you no longer need to manually parse your ID from the arguments or pass it to your ViewModel:

composable(
    "${Routes.recall}/{id}",
    arguments = listOf(navArgument("id") { type = NavType.LongType })
) {
    RecallScreen(
        onEnd = {navController.navigateUp()}
    )
}
@Composable
fun RecallScreen(
    onEnd:() -> Unit
) {
    val recallViewModel: RecallViewModel = viewModel()
}
Related