Search code examples
androidandroidxandroid-architecture-navigationandroid-navigation

Log fragments in backstack


I'm using Android Navigation. To support debugging I wanted to be able to log the entries in the backstack. I can see the number of fragments on the backstack, but I haven't found a way to identify what they are. For example, the following just appears to give me a bunch of UIDs. Ideally, I would like a list of fragment class names, or values from the name tag in the nav graph.

navHostFragment.getChildFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
    @Override
    public void onBackStackChanged() {
        String msg = {"Backstack has " + navHostFragment.getChildFragmentManager().getBackStackEntryCount() + " entries."};
        for(int i=0; i< navHostFragment.getChildFragmentManager().getBackStackEntryCount(); i++) {
            FragmentManager.BackStackEntry entry = navHostFragment.getChildFragmentManager().getBackStackEntryAt(i);
            msg += System.lineSeparator() + entry.getName();
        }
}

Result:

2022-11-23 10:35:23.292 29682-29682/com.my.app V/MainActivity: Backstack has 2 entries.
    4e403af8-ca67-41f4-9175-462913536ee7
    f8fad2fa-4e8e-4e4b-8e2b-07b15aa18cb0

Solution

  • I would like a list of fragment class names, or values from the name tag in the nav graph.

    Unfortunately we can't access fragment name or android:name of xml. because they doesn't exist in public variables in NavigationComponent classes.

    But android:id, app:route and its argument are available that you can access them for your debugging:

    navHostFragment.navController.addOnDestinationChangedListener { controller, _, _ ->
        controller.backQueue
            .joinToString(separator = "\n", prefix = "backStack: [ ", postfix = " ]") { entry ->
                buildString {
                    append(" route=")
                    append(entry.destination.route)
                    append(" idName=")
                    append(entry.destination.displayName)
                    append(" UID=")
                    append(entry.id)
                    append(" args=")
                    append(entry.arguments?.let { args -> args.keySet().associateWith { args.get(it) } })
                }
            }
    }
    

    and the result will be this for below graph:

    Graph:

    <fragment
        android:id="@+id/destination_reading"
        android:name="com.example.app.ReadingDialog">
        <argument
            android:name="article"
            android:defaultValue="@null"
            app:argType="string"
            app:nullable="true" />
    </fragment>
    

    Log:

    I/Timber GuestFragment: backStack: [  
         route=null idName=com.example.app:id/profile_graph UID=a9c2f467-03af-486e-8ab6-03fcf2f78d23 args:null 
         route=null idName=com.example.app:id/destination_reading UID=1677eb2b-6b20-4646-9e04-105a291051a0 args:{article=terms-and-conditions} ]