As mentioned in the previous article, the Fragment is repeatedly destroyed and rebuilt every time you switch destinations. It is ok to develop it according to the idea that only one activity is required for each APP recommended by Google. However, the fragment here is used as the three resident pages of the home page, and we hope to save it. After all, the destruction and reconstruction need to request network data again and re-initialize the view, which seriously affects the user experience. Then, we will continue the analysis of the previous article and support the reuse of the fragment.

Jetpack note code

This article source code is based on SDK 29, IDE is Android Studio 3.5.3

To solve

Add some logs to the items in the previous article, cut from the panel page to the notification page, and from the notification page back to the panel page to view the logs,


Create a FixFragmentNavigator, inherit the FragmentNavigator, and rewrite the Navigate method to copy the parent’s implementation directly. The first step is to reuse the fragment where it is initialized:

//FixFragmentNavigator.java
NavDestination navigate(a){
    //fix 1: Use the class name as a tag to find existing fragments
    // If you want to reuse only individual fragments, you can add some tags to the fragment, such as a prefix, which is not expanded here.
    Fragment frag = mFragmentManager.findFragmentByTag(className);
    if (null == frag) {
        // If it does not exist, it is createdfrag = instantiateFragment(mContext, mFragmentManager, className, args); }}Copy the code

Step 2, replace ft. Replace with show and hide,

//FixFragmentNavigator.java
NavDestination navigate(a){
    // ft.replace(mContainerId, frag);
    //fix 2: replace with show and hide
    List<Fragment> fragments = mFragmentManager.getFragments();
    for (Fragment fragment : fragments) {
        ft.hide(fragment);
    }
    if(! frag.isAdded()) { ft.add(mContainerId, frag, className); } ft.show(frag); ft.setPrimaryNavigationFragment(frag); }Copy the code

Step 3, reflection gets the parent class’s mBackStack,

//FixFragmentNavigator.java
NavDestination navigate(a){
    //fix 3: The mBackStack is private and not exposed, only reflected
    ArrayDeque<Integer> mBackStack;
    try {
        Field field = FragmentNavigator.class.getDeclaredField("mBackStack");
        field.setAccessible(true);
        mBackStack = (ArrayDeque<Integer>) field.get(this);
    } catch (Exception e) {
        e.printStackTrace();
        return null; }}Copy the code

Step 4: Copy the parent class’s private method generateBackStackName

//FixFragmentNavigator.java
//fix 4: Copy from the parent class
private String generateBackStackName(int backStackIndex, int destId) {
    return backStackIndex + "-" + destId;
}
Copy the code

Step 5, annotate the FixFragmentNavigator and give it a name, and then the reason says,

@Navigator.Name("fixFragment")
//fix 5: specifies a name for navigation, activity, fragment, and dialog
class FixFragmentNavigator extends FragmentNavigator {}Copy the code

Now that you have FixFragmentNavigator written, you can view the Jetpack note code for the full code. How do you use it next?

First remove app:navGraph=”@navigation/mobile_navigation” from the layout file, then go to the activity and write the following code,

//NavigationActivity.java
void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_navigation);
    BottomNavigationView navView = findViewById(R.id.nav_view);

    // Get the page container NavHostFragment
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    // Get the navigation controller
    NavController navController = NavHostFragment.findNavController(fragment);
    // Create a custom Fragment navigator
    FixFragmentNavigator fragmentNavigator =
        new FixFragmentNavigator(this, fragment.getChildFragmentManager(), fragment.getId());
    // Get the navigator provider
    NavigatorProvider provider = navController.getNavigatorProvider();
    // Add a custom Fragment navigator
    provider.addNavigator(fragmentNavigator);
    // Manually create the navigation chart
    NavGraph navGraph = initNavGraph(provider, fragmentNavigator);
    // Set the navigation diagram
    navController.setGraph(navGraph);
    // The bottom navigation sets the click event
    navView.setOnNavigationItemSelectedListener(item -> {
        navController.navigate(item.getItemId());
        return true;
    });
}

// Manually create the navigation chart and add the three destinations
private NavGraph initNavGraph(NavigatorProvider provider, FixFragmentNavigator fragmentNavigator) {
    NavGraph navGraph = new NavGraph(new NavGraphNavigator(provider));

    // Create a destination with a custom navigator
    FragmentNavigator.Destination destination1 = fragmentNavigator.createDestination();
    destination1.setId(R.id.navigation_home);
    destination1.setClassName(HomeFragment.class.getCanonicalName());
    destination1.setLabel(getResources().getString(R.string.title_home));
    navGraph.addDestination(destination1);

    / / to omit
    navGraph.addDestination(destination2);
    / / to omit
    navGraph.addDestination(destination3);
 navGraph.setStartDestination(R.id.navigation_home);  return navGraph; } Copy the code

The specific process is written in the code comments, so the reuse of fragments is realized.

NavigatorProvider: @navigator.name (“fixFragment”); NavigatorProvider: @Navigator.name (“fixFragment”)

//NavigatorProvider.java
private final HashMap<String, Navigator<? extends NavDestination>> mNavigators =
            new HashMap<>();

// "navigation" NavGraphNavigator
// "activity" ActivityNavigator
// "fragment" FragmentNavigator
// "dialog" DialogFragmentNavigator
// "fixFragment" FixFragmentNavigator this is our custom navigator
Copy the code

You then bind the navigator to the destination by creating the destination using the custom FixFragmentNavigator createDestination. It can be seen that the idea of Navigation is to abstract all types of pages as Destination for unified jump. Different navigators encapsulate the realization of different types of page jumps and are uniformly scheduled by NavController. And many, many destinations are woven into a NavGraph.

reference

  • Imooc-jetpack develops short video applications for practical use

This article is formatted using MDNICE