Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack-navigation

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


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()}
            )
        }


Solution

  • 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()
    }