0

So I have an app that has the following layout

Activity -> ViewPager -> FragmentA -> FragmentContainerView -> FragmentB

FragmentContainerView contains a NavHostFragment, which displays FragmentB using a nav_graph. There is a button in FragmentB that navigates to a new instance of FragmentB. So the Nav graph is basically just one fragment that has a link to itself.

Now if I have the FragmentContainerView directly in my activity, this works fine. However, if I put the FragmentContainerView inside another fragment inside a ViewPager, the back button no longer allows me to navigate the FragmentB navgraph.

I am using app:defaultNavHost="true" on the FragmentContainerView, but it doesnt help.

Any idea what I'm doing wrong, and what could I do to fix it?

Olli
  • 375
  • 5
  • 15

1 Answers1

2

As per the Fragment Manager guide:

Consider the navigation structure as a series of layers, with the activity as the outermost layer, wrapping each layer of child fragments underneath. Each layer must have a single primary navigation fragment. When the Back event occurs, the innermost layer controls navigation behavior. Once the innermost layer has no more fragment transactions from which to pop back, control returns to the next layer out, and this process repeats until you reach the activity.

So while app:defaultNavHost="true" is setting the NavHostFragment inside your FragmentA as the primary navigation fragment in its layer (the childFragmentManager layer of FragmentA), FragmentA must also be set as the primary navigation fragment in order for any system back button events to make it to FragmentA at all.

That same page brings up how to do that:

To define the primary navigation fragment inside of a fragment transaction, call the setPrimaryNavigationFragment() method on the transaction, passing in the instance of the fragment whose childFragmentManager should have primary control.

While ViewPager2 has APIs to allow you to set the primary navigation fragment to the current page, ViewPager1 has no such API (one of the many reasons why you should absolutely move to ViewPager2).

As a workaround for this in ViewPager1, FragmentA could set itself as the primary navigation fragment in onResume():

public fun onResume() {
    super.onResume()
    parentFragmentManager
        .beginTransaction()
        .setPrimaryNavigationFragment(this)
        .commit()
}
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Thanks! I actually use ViewPager2.. just forgot to mention it because i didn't remember there were 2 of them. However, I cant get any of the code in your link to work.. for some reason none of the functions or types youre using are defined inside my adapter.. I'm inheriting `FragmentStateAdapter`, and for example `registerFragmentTransactionCallback()` is an unresolved reference – Olli Jul 31 '21 at 19:54
  • Are you using [ViewPager2 `1.1.0-alpha01`](https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-alpha01) as specifically mentioned in that answer? – ianhanniballake Jul 31 '21 at 20:18
  • nope, seems like that was the issue! Thanks again. – Olli Jul 31 '21 at 20:28