Fragment savedInstanceState is always null when using Navigation Component
C

2

17

Currently, I am playing around Android Navigation Component with Bottom Navigation Bar. While playing I realized two facts:

  • Fragments are always recreated (onCreate, onViewCreated, onViewDestroyed are called as soon as the user navigates to another fragment)
  • savedInstanceState is always null (in onCreate, onViewCreated, etc.)

The first issue can be fixed by using custom FragmentNavigator, which will reuse fragment if it already exists

package am.chamich.apps.advancedbottomnavigation.navigator

import android.content.Context
import android.os.Bundle
import androidx.navigation.NavDestination
import androidx.navigation.NavOptions
import androidx.navigation.Navigator
import androidx.navigation.fragment.FragmentNavigator


@Navigator.Name("retain_state_fragment")
class RetainStateFragmentNavigator(
    private val context: Context,
    private val manager: androidx.fragment.app.FragmentManager,
    private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {

    override fun navigate(
        destination: Destination,
        args: Bundle?,
        navOptions: NavOptions?,
        navigatorExtras: Navigator.Extras?
    ): NavDestination? {
        val tag = destination.id.toString()
        val transaction = manager.beginTransaction()

        val currentFragment = manager.primaryNavigationFragment
        if (currentFragment != null) {
            transaction.detach(currentFragment)
        }

        var fragment = manager.findFragmentByTag(tag)
        if (fragment == null) {
            val className = destination.className
            fragment = instantiateFragment(context, manager, className, args)
            transaction.add(containerId, fragment, tag)
        } else {
            transaction.attach(fragment)
        }

        transaction.setPrimaryNavigationFragment(fragment)
        transaction.setReorderingAllowed(true)
        transaction.commit()

        return destination
    }
}

Question

For the second issue, I have no idea how to fix it, actually, I even didn't understand how the fragment is restoring its state (for example when you rotate the screen), I tied to use fragment.setInitialSavedState(savedState) to save and restore fragment state, but that doesn't help in this situation.

Actually what I need to know is when fragment view was recreated

Here is a link to my GitHub project, any help is welcome.

Consent answered 22/4, 2019 at 20:56 Comment(6)
you can check the lifecyle of fragments here developer.android.com/guide/components/fragmentsAbamp
@ErginErsoy I know the lifecycle of fragments, but that does not help to fix the issue, the issue is that saveInstanceState is always null, even when the fragment is reattachedConsent
did you check this answer for that issue #20550516Abamp
@ErginErsoy yes I checked it, I even tried it. Doesn't work at all :(Consent
@ErginErsoy you can check out my project and try to run it, there are quite a huge amount of logs when clicking on navigation items you will see in the logs that saveinstance state is always null :(Consent
Firstly, your RetainStateFragmentNavigator is not being used at all. To use it, do the following: 1. Extend MyNavigationHostFragment from NagivationHostFragment 2. Override createFragmentNavigator() function in MyNavigationHostFragment override fun createFragmentNavigator(): Navigator<out FragmentNavigator.Destination> { return RetainStateFragmentNavigator(requireContext(), childFragmentManager, id) } 3. Use MyNavigationHostFragment as in place of default navigation host fragment in your activity_main.xml 4. Now debug further to resolve the issue.Ouster
A
0

Fragment will save its state only when activity is recreated (e.g. screen rotation) and changing the fragment doesn't matter. From documentation:

There are many situations where a fragment may be mostly torn down (such as when placed on the back stack with no UI showing), but its state will not be saved until its owning activity actually needs to save its state.

Source

Saving custom state:

Put this method inside fragment:

override fun onSaveInstanceState(outState: Bundle) {
    outState.putString("text", "some value")
    super.onSaveInstanceState(outState)
}

And read the value, for example, inside onViewCreated:

val text = savedInstanceState?.getString("text")

You will receive desired value after screen rotation / phone language change or other config changes - when activity (and fragment) is being recreated.

Acerb answered 29/4, 2019 at 13:26 Comment(0)
S
-1

Check this Blog, http://www.androiddevelopment.co.in/2019/05/how-to-save-android-activity-state.html, This Blog explain how to save activity state when the activity is destroyed.

For example, If you change the language of your phone while the activity was running (and so different resources from your project need to be loaded). Another very common scenario is when you rotate your phone to the side so that the activity is recreated and displayed in landscape. You can use this technique to store instance values for your application (selections, unsaved text, etc.).

Stative answered 2/5, 2019 at 7:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.