Issue
When using the Navigation component, it is simple to navigate to the next fragment and also simple to pop back to the previous fragment.
Navigation.findNavController(v).navigate(R.id.action1);
/*vs*/
Navigation.findNavController(v).popBackStack();
How can I check within onViewCreated()
how startDestination / topLevel destination fragments were reached? If it was poped back to I want to run different code compared to when it was newly navigated to.
Update thanks to @Thracian for the suggestions:
I tested:
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
Log.d("MAIN", "New destination ID: " + destination.getDisplayName());
}
});
But it returns the same result, whether I directly navigate to a fragment or use popBack/navigateUp, so it does not help to distinguish.
I tested:
navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
navHostManager = navHostFragment.getChildFragmentManager();
navHostManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
int backStackEntryCount = navHostManager.getBackStackEntryCount();
int fragmentCount = navHostManager.getFragments().size();
Log.e("MAIN","backStackEntryCount: "+backStackEntryCount+", fragmentCount: " + fragmentCount);
}
});
Unfortunately the fragment I try to solve this for is the startDestination. Hence the backStackEntryCount
is always 0 when I reach it, both for navigateTo and for navigateUp ...
For my other top-level destinations this does also not properly work, as they always show backStackEntryCount = 1
independent of how I reach them.
Solution
I finally solved the issue.
Thanks to @Thracian to pointing me towards navHostManager.getBackStackEntryCount()
and the two Listeners that were crucial for debugging.
I solved it now via overriding onBackPressed()
:
@Override
public void onBackPressed(){
if (navController.getPreviousBackStackEntry() == null ||
navController.getCurrentBackStackEntry() == null ||
navController.getCurrentBackStackEntry()
.getDestination().getId() == R.id.nav_dashboardFragment)
Log.d("MAIN", "back pressed on Dashboard");
else {
Log.d("MAIN", "Back pressed. Target: " + navController.getPreviousBackStackEntry().getDestination().getDisplayName());
Bundle args = new Bundle();
args.putInt(DashboardFragment.KEY_CANCEL_ANIMATION_ID, 1);
if (navHostManager.getBackStackEntryCount() > 1)
navController.navigateUp();
else
navController.navigate(R.id.nav_dashboardFragment, args,
new NavOptions.Builder().setPopUpTo(R.id.nav_dashboardFragment, true).build());
}
}
I first check whether I am already on the start destination. If not I check whether getBackStackEntryCount() > 1
to understand whether the next pop back would be the start destination or not. If the next would be the start destination I do not call navigateUp()
but instead a direct navigate() with an argument that tells the fragment and most important NavOptions
that clear the backstack to not double the startDestination in the back stack (didn't work without the NavOptions).
In the Fragment I then added:
if (getArguments() != null && getArguments().get(KEY_CANCEL_ANIMATION_ID) != null) {
Log.d("DashV", "cancel animation detected");
motionLayout.setProgress(1);
}
To cancel the animation in case the argument is found.
Answered By - Tobi
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.