1

I just updated the dependencies for:

androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" }

From:

nav3Core = "1.0.0-alpha03"
lifecycleViewmodelNav3 = "1.0.0-alpha01"

To:

nav3Core = "1.0.0-alpha04"
lifecycleViewmodelNav3 = "1.0.0-alpha02"

As announced here and here, and the onCleared() function inside the ViewModel is not called anymore. With the previous versions, it worked fine. How to solve this issue?

Edit:

I tried to reproduce the issue in the simplest way possible. I only have two screens and I navigate from one screen to another on a button click. So here is my code:

@Composable
fun AppNavDisplay(
    backStack: NavBackStack
) {
    NavDisplay(
        entryDecorators = listOf(
            rememberSceneSetupNavEntryDecorator(),
            rememberSavedStateNavEntryDecorator(),
            rememberViewModelStoreNavEntryDecorator()
        ),
        backStack = backStack,
        onBack = {
            backStack.removeLastOrNull()
        },
        entryProvider = entryProvider {
            entry<Screen.SignIn> {
                SignInScreen(
                    onClearAndNavigate = backStack::onClearAndNavigate
                )
            }
            entry<Screen.Main> {
                MainScreen(
                    onClearAndNavigate = backStack::onClearAndNavigate
                )
            }
        }
    )
}

fun NavBackStack.onClearAndNavigate(screen: Screen) {
    clear()
    add(screen)
}

Here is my SignInViewModel:

class SignInViewModel(
    private val repo: AuthRepository
): ViewModel() {
    val signInState = ResponseStateHandler<Unit>()

    fun signIn() = viewModelScope.launch {
        try {
            signInState.setLoading()
            repo.signIn()
            signInState.setSuccess(Unit)
        } catch (e: Exception) {
            signInState.setFailure(e.message!!)
        }
    }

    override fun onCleared() {
        Log.d(TAG, "signInViewModel.onCleared") //Not called
        signInState.setIdle()
    }
}

And here is how to use the result in the UI:

val signInResponse by viewModel.signInState.collect()

LaunchedEffect(signInResponse) {
    signInResponse.onSuccess {
        onClearAndNavigate(Screen.Main)
    }.onFailure { message ->
        showMessage(context, "$message")
        viewModel.signInState.setIdle()
    }
}

The only thing that makes the onCleared not to be called, is the upgrade of the dependencies.

Edit2:

Here are the screens:

Scaffold(
    modifier = Modifier.fillMaxSize()
) { innerPadding ->
    Box(
        modifier = Modifier.fillMaxSize().padding(innerPadding),
        contentAlignment = Alignment.Center
    ) {
        Button(
            onClick = viewModel::signIn,
            enabled = !isProcessing
        ) {
            Row(
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = "SignIn"
                )
                Spacer(
                    modifier = Modifier.width(4.dp)
                )
                if (isProcessing) {
                    CircularProgressIndicator(
                        modifier = Modifier.size(12.dp),
                        strokeWidth = 2.dp
                    )
                }
            }
        }
    }
}

And:

val isUserSignedOut by viewModel.isSignedOutState.collectAsStateWithLifecycle()

LaunchedEffect(isUserSignedOut) {
    if (isUserSignedOut) {
        onClearAndNavigate(Screen.SignIn)
    }
}

Scaffold(
    modifier = Modifier.fillMaxSize()
) { innerPadding ->
    Box(
        modifier = Modifier.fillMaxSize().padding(innerPadding),
        contentAlignment = Alignment.BottomCenter
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            Button(
                onClick = viewModel::deleteUser,
                enabled = !isProcessing
            ) {
                Text(
                    text = "SignOut"
                )
                Spacer(
                    modifier = Modifier.width(4.dp)
                )
                if (isProcessing) {
                    CircularProgressIndicator(
                        modifier = Modifier.size(12.dp),
                        strokeWidth = 2.dp
                    )
                }
            }
        }
    }
}

Edit3:

sealed interface Screen: NavKey {
    @Serializable
    data object Main : Screen
    @Serializable
    data object SignIn : Screen
}
12
  • 1
    You can use older version then, or check the issue tracker: partnerissuetracker.corp.google.com/issues/390201791 Commented Jun 19 at 13:00
  • @TejasSoni Yes, I can use the older versions, but how about the new versions? How can make them work? Commented Jun 19 at 13:04
  • @AlwaysLearner its possible there is a bug with the latest version, you are using alpha versions after all Commented Jun 19 at 13:07
  • @tyczj Yes, that's correct, it's an alpha version, but a really important feature has stopped working :( Commented Jun 19 at 13:11
  • 3
    Sometimes that happens with alpha versions, you should never rely on them or use them in production. You can see in the link above that someone already posted about it in the issue tracker Commented Jun 19 at 13:13

2 Answers 2

1

Starting from today, 2025-07-03, with the new updates from here and here:

nav3Core = "1.0.0-alpha05"
lifecycleViewmodelNav3 = "1.0.0-alpha03"

Everything works fine. The ViewModel#onCleared is called now as expected.

Sign up to request clarification or add additional context in comments.

Comments

0

Based on the official docs, viewModels are scoped to the Activity or Fragment by default.

You can scope the viewModels to the Individual navEntrys by adding a decorator to the entryDecorators parameter:

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSceneSetupNavEntryDecorator(),
        rememberSavedStateNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.