Search code examples
androidandroid-menuandroid-architecture-navigation

How to get back where user left off when navigated to a nested graph when navigated form option menu item?


I have an app which requires multiple paired devices. From the flow of the app, there are multiple places where you can initialize pairing flow.

So I have the pairing flow as nested graph, and in root graph, I have a global action pairing_action. And inside the nested graph, I have another global action finish_pairing.

The problem is, when I call finish_pairing action from the pairing fragments, I always ends up at the main screen regardless from where I initiated the pairing flow.

But that's not what I want, I want to get back to the screen where I initiated the pairing flow from (where I left off when entering the pairing flow).

Code given below.

navigation.xml

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation"
    app:startDestination="@id/start_fragment">

    <!-- Global action to start pairing -->
    <action android:id="@+id/pairing_action"
        app:destination="@id/pairing"/>

    <fragment ... />
    <fragment ... />
    <fragment ... />

    <!-- Nested pairing flow -->
    <navigation android:id="@+id/pairing"
        android:label="Pairing"
        app:startDestination="@id/pairing_fragment">

        <!-- Nested global action to finish pairing -->
        <!-- Should get to the fragment which initiated pairing! -->
        <action android:id="@+id/finish_pairing"
            app:popUpTo="@id/pairing"
            app:popUpToInclusive="true" />

        <fragment ... />
        <fragment ... />
        <fragment ... />
    </navigation>
</navigation>

nested pairing nav graph

Android Studio

EDIT 1:

I get back to the main screen even when I press back button from the pairing flow.

Example: I get to the pairing screen like this:

main -> devices -> pairing -> enter code

Now when I call the finish_pairing global action from enter code screen (or press back 2 time), I want to return back to the devices screen. But I end up on the main instead.

EDIT 2:

This is the logcat when going from devices screen to pairing graph:

V/FragmentManager: Commit: BackStackEntry...
D/FragmentManager: mName=2-2131231057 mIndex=-1 mCommitted=false
...
D/FragmentManager: Operations:
D/FragmentManager: Op #0: REPLACE PairingFragment...
...
D/FragmentManager: Op #1: SET_PRIMARY_NAV PairingFragment...
...
V/FragmentManager: Run: BackStackEntry...
V/FragmentManager: Bump nesting in BackStackEntry... by -1
V/FragmentManager: Bump nesting of StartFragment... to 1
V/FragmentManager: Bump nesting of StartFragment... to 0
V/FragmentManager: Bump nesting of DevicesFragment... to 1
V/FragmentManager: Bump nesting of DevicesFragment... to 0
V/FragmentManager: remove: DevicesFragment... nesting=0

V/FragmentManager: add: StartFragment...
V/FragmentManager: Bump nesting in BackStackEntry... by 1
V/FragmentManager: Bump nesting of StartFragment... to 1
V/FragmentManager: Bump nesting of StartFragment... to 2
V/FragmentManager: Bump nesting of PairingFragment... to 1
V/FragmentManager: Bump nesting of PairingFragment... to 2
V/FragmentManager: remove: StartFragment... nesting=2

V/FragmentManager: add: PairingFragment...
V/FragmentManager: Added fragment to active set PairingFragment...
V/FragmentManager: moveto CREATED: PairingFragment...
V/FragmentManager: moveto ACTIVITY_CREATED: PairingFragment...
V/FragmentManager: moveto STARTED: PairingFragment...
V/FragmentManager: moveto RESUMED: PairingFragment...

V/FragmentManager: movefrom RESUMED: DevicesFragment...
V/FragmentManager: movefrom STARTED: DevicesFragment...
V/FragmentManager: movefrom ACTIVITY_CREATED: DevicesFragment...
W/FragmentManager: moveToState: Fragment state for DevicesFragment... not updated inline; expected state 1 found 2
V/FragmentManager: movefrom CREATED: DevicesFragment...
D/FragmentManager: Clearing non-config state for DevicesFragment...
D/FragmentManager: onCleared called for FragmentManagerViewModel{a60610c} Fragments () Child Non Config () ViewModelStores ()
V/FragmentManager: Removed fragment from active set DevicesFragment...

It seems that when navigating to pairing graph, backstack was popped (first devices screen then start screen) and then go to pairing screen.

Isn't it a bug? Why should global action pop backstack?!

I am using options menu items to get into the pairing flow.


Solution

  • I use menu navigation heavily in my app. NavigationUI supports it. But if you read the documentation carefuly, there is this little remark:

    By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.

    And this was the reason why entering pairing screens from devices screens "broke" the back stack.

    So the solution was adding android:menuCategory="secondary" to the menu on devices screen, and it started working as expected.