Reputation: 1333
I changed delegate from viewModels
to hiltNavGraphViewModels
and it's works. Thanks to ianhanniballake's comments. But now is another issue. If app have killed (Logcat -> Terminate App), occurs exception No destination with ID 2131296453 is on the NavController's back stack. The current destination is null
(stacktrace below). How can I restore back stack in order to hiltNavGraphViewModels
don't fail?
@AndroidEntryPoint
class ScriptDetailFragment: Fragment(R.layout.component_detail_script) {
private val viewModel: SharedViewModel by hiltNavGraphViewModels(R.id.scriptFragment)
}
@AndroidEntryPoint
class ScriptFragment : Fragment(R.layout.component_script) {
private val viewModel: SharedViewModel by hiltNavGraphViewModels(R.id.scriptFragment)
fun navigateToDetail(navDirection: NavDirections) {
findNavController().navigate(navDirection)
}
}
@HiltViewModel
class SharedViewModel @Inject constructor(
private val componentWrapper: ComponentWrapper
) : ViewModel() {
}
dependencies {
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'com.google.dagger:hilt-android:2.38'
implementation("androidx.hilt:hilt-navigation-fragment:1.0.0")
kapt 'com.google.dagger:hilt-compiler:2.38'
kapt 'androidx.hilt:hilt-compiler:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.fragment:fragment-ktx:1.5.4"
implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"
implementation "androidx.navigation:navigation-ui-ktx:2.5.3"
}
Caused by: java.lang.IllegalArgumentException: No destination with ID 2131296453 is on the NavController's back stack. The current destination is null
at androidx.navigation.NavController.getBackStackEntry(NavController.kt:2209)
at *.pages.departure.ScriptFragment$special$$inlined$hiltNavGraphViewModels$1.invoke(HiltNavGraphViewModelLazy.kt:49)
at *.pages.departure.ScriptFragment$special$$inlined$hiltNavGraphViewModels$1.invoke(Unknown Source:0)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at *.pages.departure.ScriptFragment$special$$inlined$hiltNavGraphViewModels$3.invoke(HiltNavGraphViewModelLazy.kt:57)
at *.pages.departure.ScriptFragment$special$$inlined$hiltNavGraphViewModels$3.invoke(Unknown Source:0)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:47)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35)
at *.pages.departure.ScriptFragment.getViewModel(ScriptFragment.kt:15)
at *.pages.departure.ScriptFragment.onViewCreated(ScriptFragment.kt:20)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3128)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
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.dispatchViewCreated(FragmentManager.java:2888)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3129)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
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.dispatchActivityCreated(FragmentManager.java:2895)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:351)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:248)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1335)
at android.app.Activity.performStart(Activity.java:7043)
activity_main.xml
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
tools:context=".screens.MainActivity" />
MainActivity.ki
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
configureNavHost()
}
override fun onSupportNavigateUp() = navController.navigateUp() || super.onSupportNavigateUp()
private fun configureNavHost() {
val resId = if (dsr.isFirstLaunch.value) R.id.welcomeFragment else R.id.webViewFragment
navController = (supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment).navController
navController.navInflater.inflate(R.navigation.nav_graph).let { graph ->
graph.setStartDestination(resId)
navController.graph = graph
}
}
}
Upvotes: 0
Views: 607
Reputation: 7815
If the app is killed and then restarted, the Navigation graph and the back stack will be reset. This means that any fragments or destinations that were on the back stack will be removed, and the NavController
will no longer be able to find them.
In order to restore the back stack and avoid the exception, you can use the onSaveInstanceState()
method in Fragment
or Activity
to save the state of the NavController
and the back stack. This will allow to restore the stored state when the app is restarted.
Example of implementation in a Fragment
:
@AndroidEntryPoint
class MyFragment : Fragment() {
private val navController by lazy { findNavController() }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Save the state of the NavController and the back stack
navController.saveState(outState)
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
// Restore the state of the NavController and the back stack
savedInstanceState?.let { navController.restoreState(it) }
}
}
With this implementation, the state of the NavController
and the back stack will be saved when the app is killed and restored when the app is restarted, allowing the hiltNavGraphViewModels()
function to find the correct destination and avoid the exception.
Upvotes: 2