Abhimanyu
Abhimanyu

Reputation: 14787

View Model not destroyed on back press in jetpack compose

I am aware there are many similar questions and I have gone through them, still my issue is not solved.

Minified example of my problem,
I have 2 composables ScreenA and ScreenB.
Both composables have separate viewmodels. I am starting at screen A and navigating to screen B. On back button press, I expect the screen B view model to be destroyed. So when I navigate again to screen B, I want its viewmodel to be created again.

ScreenA

@Composable
fun ScreenA(
    screenViewModel: ScreenAViewModel = hiltViewModel(),
) { 
  // Compose code
}

ScreenB

@Composable
fun ScreenB(
    screenViewModel: ScreenBViewModel = hiltViewModel(),
) { 
  // Compose code
}

From the Hilt and Jetpack Navigation Docs, my understanding is using hiltViewModel() should scope the viewmodel to the particular composable. I am not clear if there is some mistake there.

How I have verified that the view model is not destroyed?

Added a breakpoint in screen B viewmodel init block. It is reaching init only once when I navigate back and forth.

Referred Questions
How to destroy a ViewModel when user leave a screen
How to share a viewmodel between two or more Jetpack composables inside a Compose NavGraph?
Activity view model in Jetpack compose
Android Compose Navigation and ViewModel lifecycle
Different viewmodel for different composable functions inside same activity

Sample repo with minimum reproducible code - https://github.com/Abhimanyu14/compose-navigation-sample

Upvotes: 4

Views: 4814

Answers (1)

Abhimanyu
Abhimanyu

Reputation: 14787

The issue was, I was using using CompositionLocalProvider incorrectly.

This was my initial code.

@Composable
fun MyNavGraph(
    activityViewModel: MainActivityViewModel,
    viewModelStoreOwner: ViewModelStoreOwner,
) {
    val navHostController = rememberNavController()
    val myNavActions = remember(navHostController) {
        MyNavActions(navHostController)
    }

    NavHost(
        navController = navHostController,
        startDestination = Screen.Home.route,
    ) {
        composable(
            route = Screen.Home.route,
        ) { navBackStackEntry ->
            CompositionLocalProvider(
                LocalViewModelStoreOwner provides viewModelStoreOwner
            ) {
                HomeScreen(
                    activityViewModel = activityViewModel,
                    navigateToSettings = {
                        myNavActions.navigateTo(
                            navBackStackEntry,
                            Screen.Settings.route,
                        )
                    },
                )
            }
        }
        composable(
            route = Screen.Settings.route,
        ) { navBackStackEntry ->
            CompositionLocalProvider(
                LocalViewModelStoreOwner provides viewModelStoreOwner
            ) {
                SettingsScreen(
                    activityViewModel = activityViewModel,
                )
            }
        }
    }
}

Removing

CompositionLocalProvider(
    LocalViewModelStoreOwner provides viewModelStoreOwner
)

fixed the scoping of the viewmodel to composable scope.

Sample repo with initial commit and fixed commit -
https://github.com/Abhimanyu14/compose-navigation-sample

Upvotes: 0

Related Questions