We need to implement a state-machine driven navigation, where the currently shown screen depends on current state. As such, our approach so far has been to use global actions and navigate to the right screen whenever the state changes. On first look, everything seemed to work great, however, we've started noticing some weird behaviours when using the app:popUpTo
attribute on the actions.
In our concrete case, we have 2 sub nav graphs (let's call them NG1
and NG2
), where NG2
is state-machine driven. Let's say we're in screen A
in NG1
and then we navigate to NG2
, which adds screen B
. We now have 2 options:
- If we navigate to screen
C
(inNG2
) using an action withapp:popUpTo="@+id/NG2"
(effectively aiming to replaceB
withC
), then, sometimes, FragmentA
briefly starts (onStart
) for a few tens of milliseconds and then stops, before startingC
. So instead ofB -> C
, we getB -> A -> C
. It seems that an action with apopUpTo
, is not transactional. - If we navigate to screen
C
(inNG2
) using an action withoutapp:popUpTo="@+id/NG2"
, screenA
does not start, butB
is left in the back stack. As such, if screenB
needs to be shown again, we end up with a backstack looking likeA / B / C / B
, which is not what we're aiming for.
Of course, the behaviour we're looking for is the one attempted in 1, where we can move from a screen X
to a screen Y
to a screen Z
, with popping Y
, but not briefly starting X
. Is there anything we're doing wrong or is it a bug in the android-navigation
component?
I'm also adding some logs, showing actual logs that I've just replicated (timestamps are actual):
// Here we navigate from A to B
2020-03-09 19:14:14.999 BaseAppNavigator: Navigating to directions: com.example.app:id/toNavGraph2
2020-03-09 19:14:15.006 BaseAppNavigator.OnDestinationChangedListener: Navigation destination changed: com.example.app:id/fragmentB
2020-03-09 19:14:15.007 BaseAppNavigator.OnDestinationChangedListener: Active navigation graph changed to: com.example.app:id/navGraph2
2020-03-09 19:14:15.235 BaseViewModelFragment: OnStart: FragmentB
2020-03-09 19:14:15.247 BaseViewModelFragment: OnStop: FragmentA
// Here we trigger navigate from B to C, with a destination with popUpTo="navGraph2"
2020-03-09 19:14:56.422 BaseAppNavigator: Navigating to directions: com.example.app:id/toFragmentC
2020-03-09 19:14:56.430 BaseAppNavigator.OnDestinationChangedListener: Navigation destination changed: com.example.app:id/fragmentC
2020-03-09 19:14:56.516 BaseViewModelFragment: OnStart: FragmentA
2020-03-09 19:14:56.529 BaseViewModelFragment: OnStop: FragmentB
2020-03-09 19:14:56.537 BaseViewModelFragment: OnDestroy: FragmentB
2020-03-09 19:14:56.580 BaseViewModelFragment: OnStart: FragmentC
2020-03-09 19:14:56.613 BaseViewModelFragment: OnStop: FragmentA
with the following action:
<action
android:id="@+id/toFragmentC"
app:destination="@id/fragmentC"
app:popUpTo="@+id/NavGraph2" />
from Replacing destination using NavGraph (transaction when using app:popUpTo)
No comments:
Post a Comment