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
}
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.