Anton Mironov
Anton Mironov

Reputation: 93

Android Navigation Component saveState and restoreState

Guys I need your help.

I use android navigation component and want to save backstack after user press button and restore it after. I found 2 methods

navController.saveState(): Bundle and navController.restoreState(bundle: Bundle).

But i have problem in use it. Seems like saveState work greate (i see bundle, and backstack inside), but i dont understand how to use restoreState, because the documentation says:

Restores all navigation controller state from a bundle. This should be called before any call to setGraph.

https://developer.android.com/reference/kotlin/androidx/navigation/NavController#restorestate

Okay, i did it, seems like backstack restored, but on screen i see first fragment (instead of the one I had when I saved it). What i do wrong?

Code:

FirstFragment

    private val TAG = this::class.java.name

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        btn_forward.setOnClickListener { findNavController().navigate(R.id.action_firstFragment_to_secondFragment) }
        btn_back.setOnClickListener { requireActivity().onBackPressed() }
    }

}

SecondFragment

class SecondFragment : Fragment() {
    private val TAG = this::class.java.name

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        btn_forward.setOnClickListener { findNavController().navigate(R.id.action_secondFragment_to_thirdFragment) }
        btn_back.setOnClickListener { requireActivity().onBackPressed() }
    }

}

ThirdFragment

class ThirdFragment : Fragment() {
    private val TAG = this::class.java.name

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_third, container, false)
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        btn_finish.setOnClickListener {
            (requireActivity() as MainActivity).saveState() //here save bundle
            requireActivity().finishAfterTransition()
        }
        btn_back.setOnClickListener { requireActivity().onBackPressed() }
    }

}

MainActivity

class MainActivity : AppCompatActivity() {
    private val TAG = "MySuperActivity"

    lateinit var navController: NavController
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.d(TAG, "onCreate($savedInstanceState) called")

        initNavController()
    }

    private fun initNavController() {
        val navHostFragment = nav_host_fragment as NavHostFragment
        val graphInflater = navHostFragment.navController.navInflater

        val graph = graphInflater.inflate(R.navigation.main_graph)

        navController = navHostFragment.navController
        navHostFragment.childFragmentManager
        if (App.instance.savedBundle != null) {
            Log.d(TAG, "bundle: ${App.instance.savedBundle}")
            navController.restoreState(App.instance.savedBundle)
            graph.startDestination = R.id.thirdFragment
        }

        navController.graph = graph
        Log.d(TAG, "navController.currentDestination: ${navController.currentDestination}")
        Log.d(TAG, "navController.graph.startDestination: ${navController.graph.startDestination}")
    }

    fun saveState(){
        App.instance.savedBundle = navController.saveState()
        Log.d(TAG, "saveState() : ${App.instance.savedBundle}")
    }
}

here some logs: logs

full code:github

Upvotes: 7

Views: 5264

Answers (1)

aldajo92
aldajo92

Reputation: 301

I am not sure if my answer helps you, but I had many issues trying to save the navigation state from handling rotations. The issue that I had comes from an old version of the navigation component, I update to the most recent, and it fixes the issue:

def android_navigation = '2.3.4'
implementation "android.arch.navigation:navigation-fragment-ktx:$android_navigation"
implementation "android.arch.navigation:navigation-ui-ktx:$android_navigation"
implementation "androidx.navigation:navigation-dynamic-features-fragment:$android_navigation"

Upvotes: 0

Related Questions