I am using Navigation Compose, and I am trying to pass an entire object to the next screen, So I am using a shared ViewModel
through hilt, and created a mutablestate variable of that object and want to get its value in the next screen.
Like This
var campaign = mutableStateOf<Campaign?>(null)
private set
fun addCampaign(campaign: Campaign){
this.campaign.value = campaign
}
where Campaign
is just a data-class.
In my Screen in Navigation
LazyColumn (
content =
{
items(viewModel.campaignListCurrent){ campaign ->
CampaignItem(
image = campaign.brand?.image ?: "",
title = campaign.name ,
id = campaign.id ,
description =campaign.description ,
date =campaign.createdAt ) {
viewModel.addCampaign(
CampaignsViewModel.Campaign(...) // the "campaign" object is used to fill this
)
Timber.tag("CampaignObject").v(viewModel.campaign.value.toString())
viewModel.changed = true
navController.navigate(Screen.CampaignDetailsScreen.route)
}
}
})
I can see when I log the data that it was stored successfully. yet in the next screen when I get the data from the same ViewModel, it's null. even though its a mutablestate and supposed to change its value and be observables, I don't think I get mutablestate behavior at all, and any link for a proper explanation for it will be appreciated.
val campaign by remember { viewModel.campaign }
Timber.v("CampaignDetailsScreen2: " + campaign.toString())
can someone explain to me why it doesn't work here, even if I used Launched effect?? why doesn't change its value here?
I managed to solve this by Creating a SharedViewModel instance in the NavGraph to make sure it is the same Instance used in both composable functions.
@Composable
fun CampaignsScreen(
navController : NavController,
viewModel: CampaignsViewModel
) {
....
@Composable
fun CampaignDetailsScreen(
navController : NavController,
viewModel: CampaignsViewModel
) {
and in my NavGraph I passed the ViewModel as HiltViewmodel in the constructor and from it to the two screens
@Composable
fun SetUpNavGraph (navController : NavHostController,
campaignViewModel: CampaignsViewModel = hiltViewModel()) {
...........
loginNavGraph(navController = navController)
homeNavGraph(navController = navController, campaignsViewModel = campaignViewModel)
}
}
and in the home NavGraph I passed the parametere and its the same Instance in both
fun NavGraphBuilder.homeNavGraph(
navController : NavHostController,
campaignsViewModel: CampaignsViewModel
){
navigation(startDestination = Screen.HomeScreen.route, route = HOME_GRAPH_ROUTE) {
................
composable(Screen.Campaigns.route){
CampaignsScreen(navController = navController, viewModel = campaignsViewModel)
}
composable(Screen.CampaignDetailsScreen.route){
CampaignDetailsScreen(navController, viewModel = campaignsViewModel)
}
}
}
You can use backstackEntry and PreviouseBackStack to solve this but it won't work if you have a JSON Object within your object as you will need to Serialize and Deserialize this object manually and it will take more time and code to achieve the same goal for a shared ViewModel to pass Parclized object. until Google Solve passing Parclized objects in Compose Navigation I recommend backStack Entry if you don't have a JSON object within your paralyzed object and if you do, use a shared ViewModel between the tow composable function.