I was using Jetpack Navigation Components, the problem occurred while rotating the device!
I was building an application that has three main features. These are onboarding
, auth
, and main
. Every feature has its navigation graph. If it's the first time opening the app, I have to open go with the onboarding
graph, If the user is not authenticated, go with auth
. Otherwise to main
. The problem keeps occurring while rotating the device.
The detailed exception is here:
Process: io.usdaves.chat, PID: 11247
java.lang.RuntimeException: Unable to start activity ComponentInfo{io.usdaves.chat/io.usdaves.chat.application.HostActivity}: java.lang.IllegalStateException: Restoring the Navigation back stack failed: destination io.usdaves.chat:id/navigation_auth cannot be found from the current destination null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4166)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4312)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:6468)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:6342)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2571)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Caused by: java.lang.IllegalStateException: Restoring the Navigation back stack failed: destination io.usdaves.chat:id/navigation_auth cannot be found from the current destination null
at androidx.navigation.NavController.onGraphCreated(NavController.kt:1128)
at androidx.navigation.NavController.setGraph(NavController.kt:1086)
at androidx.navigation.NavController.setGraph(NavController.kt:1039)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.kt:155)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
at androidx.fragment.app.FragmentManager.dispatchCreate(FragmentManager.java:2884)
at androidx.fragment.app.FragmentController.dispatchCreate(FragmentController.java:252)
at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:220)
at io.usdaves.chat.application.HostActivity.onCreate(HostActivity.kt:21)
at android.app.Activity.performCreate(Activity.java:8578)
at android.app.Activity.performCreate(Activity.java:8557)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4147)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4312)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:6468)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:6342)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2571)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
The directions comes from viewModel:
private const val SHOULD_KEEP_SPLASH = "should_keep_splash_saved_state_handle_key"
@HiltViewModel
class HostViewModel @Inject constructor(
preferences: UserPreferences,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val shouldKeepSplash = savedStateHandle.getStateFlow(SHOULD_KEEP_SPLASH, true)
val navigationDirections = combine(
preferences.isOnboardingCompleted(),
preferences.isLoggedIn()
) { isOnboardingCompleted, isLoggedIn ->
when {
isOnboardingCompleted && isLoggedIn -> NavigateToMainAction
isOnboardingCompleted -> NavigateToAuthAction
else -> NavigateToOnboardingAction
}.also {
savedStateHandle[SHOULD_KEEP_SPLASH] = false
}
}.distinctUntilChanged().shareIn(viewModelScope, Eagerly)
}
I'was sing this sealed class to pass navigations.
sealed class HostNavigationDirections(@NavigationRes val navigationId: Int) {
object NavigateToOnboardingAction : HostNavigationDirections(R.navigation.navigation_onboarding)
object NavigateToAuthAction : HostNavigationDirections(R.navigation.navigation_auth)
object NavigateToMainAction : HostNavigationDirections(R.navigation.navigation_main)
}
Here is the Host Activity.
@AndroidEntryPoint
class HostActivity : AppCompatActivity() {
private val viewModel: HostViewModel by viewModels()
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { viewModel.shouldKeepSplash.value }
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigationDirections.collectLatest { direction ->
val authNavGraph = navController.navInflater.inflate(direction.navigationId)
navController.graph = authNavGraph
}
}
}
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
The xml is here:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@ id/auth_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@ id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation_main" />
</FrameLayout>
I did a lot of researchers on this problem but nothing was found.
CodePudding user response:
That was the dumbest question ever. I just had to remove this line:
app:navGraph="@navigation/navigation_main"
Now it's working. Thanks to @ianhanniballake. He saved my life)