Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragments not added to backstack using Navigation Components

Information:

I'm programmatically inserting a NavHostFragment for each feature of the app. Each NavHostFragment has it's own Navigation Graph. Dagger is providing them by using a FragmentFactory specific to each feature. It's a Single Activity structure with MVVM architecture.

Repo: https://github.com/mitchtabian/DaggerMultiFeature/tree/nav-component-backstack-bug

checkout the branch "nav-component-backstack-bug".


The Problem

When navigating into the graph the fragments are not being added to the backstack. The only fragment that's added is whichever one has most recently been visited. So the stack size always stays at one.

Originally I thought it was because I wasn't setting the FragmentFactory to the ChildFragmentManager but that doesn't change anything. See the code snippets below for the relevant code. Or checkout the project and run it. I have logs printing out the fragments currently in the backstack from the ChildFragmentManager and also the SupportFragmentManager. Both have a constant size of 1.


Feature1NavHostFragment.kt

This is one of the custom NavHostFragment's. The create() function in the companion object is how I create them.


class Feature1NavHostFragment
@Inject
constructor(
    private val feature1FragmentFactory: Feature1FragmentFactory
): NavHostFragment(){

    override fun onAttach(context: Context) {
        ((activity?.application) as BaseApplication)
            .getAppComponent()
            .feature1Component()
            .create()
            .inject(this)
        childFragmentManager.fragmentFactory = feature1FragmentFactory
        super.onAttach(context)
    }

    companion object{

        const val KEY_GRAPH_ID = "android-support-nav:fragment:graphId"

        @JvmStatic
        fun create(
            feature1FragmentFactory: Feature1FragmentFactory,
            @NavigationRes graphId: Int = 0
        ): Feature1NavHostFragment{
            var bundle: Bundle? = null
            if(graphId != 0){
                bundle = Bundle()
                bundle.putInt(KEY_GRAPH_ID, graphId)
            }
            val result = Feature1NavHostFragment(feature1FragmentFactory)
            if(bundle != null){
                result.arguments = bundle
            }
            return result
        }
    }

}

MainActivity.kt

This is an example of how I create the NavHostFragment's in MainActivity.


val newNavHostFragment = Feature1NavHostFragment.create(
                                  getFeature1FragmentFactory(),
                                  graphId
                         )
supportFragmentManager.beginTransaction()
    .replace(
        R.id.main_nav_host_container,
        newNavHostFragment,
        getString(R.string.NavHostFragmentTag)
    )
    .setPrimaryNavigationFragment(newNavHostFragment)
    .commit()


Feature1MainFragment.kt

And here is an example of how I'm navigating to other fragments in the graph.


btn_go_next.setOnClickListener {
    findNavController().navigate(R.id.action_feature1MainFragment_to_feature1NextFragment)
}


Summary

Like I said, in every fragment I'm printing the backstack for both the ChildFragmentManager and the SupportFragmentManager. Both have a constant size of one. It's as if the fragments are being replaced as I navigate into the graph instead of added to the stack.

Anyways, thanks for reading this and I would appreciate any insights.

like image 840
mitch Avatar asked Jan 16 '20 18:01

mitch


1 Answers

Looks like a misunderstanding on my part (and a bug, also on my part).

If you loop through the fragments in the childFragmentManager it only ever shows the top-most fragment for some reason.

Example

val navHostFragment = supportFragmentManager
            .findFragmentByTag(getString(R.string.NavHostFragmentTag)) as NavHostFragment
val fragments = navHostFragment.childFragmentManager.fragments
for(fragment in fragments){
    // Only prints a single fragment, no matter the backstack size
}

However, if you print the backstack size like this, you will get the correct answer.

val navHostFragment = supportFragmentManager
            .findFragmentByTag(getString(R.string.NavHostFragmentTag)) as NavHostFragment
val backstackCount = navHostFragment.childFragmentManager.backStackEntryCount
println("backstack count: $backstackCount")

At the end of the day this misunderstanding caused me to believe the fragments were not being added to the backstack. All is good.

like image 187
mitch Avatar answered Oct 22 '22 05:10

mitch