Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper usage of navigation component with view pager2 and nested navigation

I am trying to build the following view structure/ navigation using ViewPager2 + FragmentStateAdapter + navigation component.

Preconditions: Single activity architecture, with one navigation graph

1. Fragment A holds a view pager. View pager uses FragmentStateAdapter.

2. Fragment B is instantiated via FragmentStateAdapter ("lives" in view pager).

3. Fragment C - should be navigated to from Fragment B. --> This is where the problem is.


Approach 1 : ViewPager2 + FragmentStateAdapter + navigation declared from Fragment B

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.abc.FragmentA"
        android:label="FragmentA" />

    <fragment
        android:id="@+id/fragmentB"
        android:name="com.abc.FragmentB"
        android:label="FragmentB">
        <action
            android:id="@+id/to_fragmentC"
            app:destination="@id/fragmentC" />
    </fragment>

    <fragment
        android:id="@+id/fragmentC"
        android:name="com.abc.FragmentC"
        android:label="FragmentC" />

FragmentB executes:

 FragmentBDirections
            .toFragmentC()
            .let { findNavController().navigate(it) }

Result :

App crash
java.lang.IllegalArgumentException: navigation destination com.abc:id/to_fragmentC is unknown to this NavController

Approach 2 : ViewPager2 + FragmentStateAdapter + navigation declared from Fragment A

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.abc.FragmentA"
        android:label="FragmentA" >
        <action
            android:id="@+id/to_fragmentC"
            app:destination="@id/fragmentC" />
    </fragment>

    <fragment
        android:id="@+id/fragmentB"
        android:name="com.abc.FragmentB"
        android:label="FragmentB">
    </fragment>

    <fragment
        android:id="@+id/fragmentC"
        android:name="com.abc.FragmentC"
        android:label="FragmentC" />

FragmentB executes:

 FragmentADirections
            .toFragmentC()
            .let { findNavController().navigate(it) }

Result:

App navigates to FragmentC, but when i hit the back button , it crashes with :
java.lang.IllegalArgumentException
        at androidx.core.util.Preconditions.checkArgument(Preconditions.java:36)
        at androidx.viewpager2.adapter.FragmentStateAdapter.onAttachedToRecyclerView(FragmentStateAdapter.java:132)
        at androidx.recyclerview.widget.RecyclerView.setAdapterInternal(RecyclerView.java:1209)
        at androidx.recyclerview.widget.RecyclerView.setAdapter(RecyclerView.java:1161)
        at androidx.viewpager2.widget.ViewPager2.setAdapter(ViewPager2.java:461)
        at com.abc.FragmentA.viewCreated(FragmentA.kt:69)


Approach 3 : ViewPager + FragmentStatePagerAdapter (deprecated) + navigation declared from Fragment B

The same result as approach 1.


Approach 4 : ViewPager + FragmentStatePagerAdapter (deprecated) + navigation declared from Fragment A

This one actually works. Also, the navigation back works fine.

The problem here is that:

  • Navigation has to be defined for every parent fragment of FragmentB -> not so scaleable
  • Usage of the adapter that is deprecated

If anybody knows some elegant solution to this problem, I would be very glad for any hints.

Thank you

like image 667
Matin Petrulak Avatar asked Nov 30 '25 02:11

Matin Petrulak


1 Answers

You don't need to declare Fragment B as a destination in your graph, because you never use NavController to navigate to it. Instead of using an action, you can just use a destination id to implement navigation in Fragment B, like findNavController().navigate(R.id.fragmentC). The findNavController method will find the parent fragment's navController to execute the navigation.

like image 175
suncunxing Avatar answered Dec 02 '25 16:12

suncunxing



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!