The activity tool for creating a Navigation interface directly in Android Studio does this for us
– When running a running project, I found that the fragment on the previous interface was destroyed. I checked the source and found that this was not a bug but a specific design The navigate method replaces the Fragment directly with its replace method
Now that we know why switching fragments are destroyed, we have a solution

Replace replace with show and hide

Without further ado, just go to the code and write a class that inherits FragmentNavigator and overrides the Navigate method
@Navigator.Name("fixFragment") //fix 5: I need to specify a name, Public Class FixFragmentNavigator extends FragmentNavigator {private} static final String TAG = "FixFragmentNavigator"; private Context mContext; private FragmentManager mFragmentManager; private int mContainerId; public FixFragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager, int containerId) { super(context, manager, containerId); mContext = context; mFragmentManager = manager; mContainerId = containerId; } @Nullable @Override public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) { if (mFragmentManager.isStateSaved()) { Log.i(TAG, "Ignoring navigate() call: FragmentManager has already" + " saved its state"); return null; } String className = destination.getClassName(); if (className.charAt(0) == '.') { className = mContext.getPackageName() + className; } //fix 1: Use the class name as a tag to find existing fragments // Can be marked on the tag do such as add a prefix) fragments frag = mFragmentManager. FindFragmentByTag (className); If (null == frag) {if (null == frag) {if (null == frag) {if (null == Frag) { } frag.setArguments(args); final FragmentTransaction ft = mFragmentManager.beginTransaction(); int enterAnim = navOptions ! = null ? navOptions.getEnterAnim() : -1; int exitAnim = navOptions ! = null ? navOptions.getExitAnim() : -1; int popEnterAnim = navOptions ! = null ? navOptions.getPopEnterAnim() : -1; int popExitAnim = navOptions ! = null ? navOptions.getPopExitAnim() : -1; if (enterAnim ! = -1 || exitAnim ! = -1 || popEnterAnim ! = -1 || popExitAnim ! = -1) { enterAnim = enterAnim ! = 1? enterAnim : 0; exitAnim = exitAnim ! = 1? exitAnim : 0; popEnterAnim = popEnterAnim ! = 1? popEnterAnim : 0; popExitAnim = popExitAnim ! = 1? popExitAnim : 0; ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim); } // ft.replace(mContainerId, frag); / / fix 2: replace with show and hide List < fragments > fragments could = mFragmentManager. GetFragments (); for (Fragment fragment : fragments) { ft.hide(fragment); } if (! frag.isAdded()) { ft.add(mContainerId, frag, className); } ft.show(frag); ft.setPrimaryNavigationFragment(frag); final @IdRes int destId = destination.getId(); //fix 3: mBackStack is private and not exposed, only ArrayDeque<Integer> mBackStack is reflected; try { Field field = FragmentNavigator.class.getDeclaredField("mBackStack"); field.setAccessible(true); mBackStack = (ArrayDeque<Integer>) field.get(this); } catch (Exception e) { e.printStackTrace(); return null; } final boolean initialNavigation = mBackStack.isEmpty(); final boolean isSingleTopReplacement = navOptions ! = null && ! initialNavigation && navOptions.shouldLaunchSingleTop() && mBackStack.peekLast() == destId; boolean isAdded; if (initialNavigation) { isAdded = true; } else if (isSingleTopReplacement) { if (mBackStack.size() > 1) { mFragmentManager.popBackStack( generateBackStackName(mBackStack.size(), mBackStack.peekLast()), FragmentManager.POP_BACK_STACK_INCLUSIVE); ft.addToBackStack(generateBackStackName(mBackStack.size(), destId)); } isAdded = false; } else { ft.addToBackStack(generateBackStackName(mBackStack.size() + 1, destId)); isAdded = true; } if (navigatorExtras instanceof Extras) { Extras extras = (Extras) navigatorExtras; for (Map.Entry<View, String> sharedElement : extras.getSharedElements().entrySet()) { ft.addSharedElement(sharedElement.getKey(), sharedElement.getValue()); } } ft.setReorderingAllowed(true); ft.commit(); if (isAdded) { mBackStack.add(destId); return destination; } else { return null; } } //fix 4: @nonNULL Private String generateBackStackName(int backStackIndex, int destId) { return backStackIndex + "-" + destId; }}Copy the code
Here is the code for the activity
public class MainActivity extends AppCompatActivity { private TextView text; private TestViewModel viewModel; // @Override // protected void onCreate(Bundle savedInstanceState) { // super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main5); // text = findViewById(R.id.text); // BottomNavigationView navView = findViewById(R.id.nav_view); // // Passing each menu ID as a set of Ids because each // // menu should be considered as top level destinations. // AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder( // R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications) // .build(); // NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); // NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); // NavigationUI.setupWithNavController(navView, navController); // viewModel = new ViewModelProvider(this).get(TestViewModel.class); // viewModel.name.observe(this, new Observer<String>() { // @Override // public void onChanged(String s) { // text.setText(s); / / / /}}); // } BottomNavigationView navView; NavController navController; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main5); text = findViewById(R.id.text); navView = findViewById(R.id.nav_view); viewModel = new ViewModelProvider(this).get(TestViewModel.class); Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment); / / get the navigation controller navController = NavHostFragment. FindNavController (fragments); FragmentNavigator = new FixFragmentNavigator(this, fragment.getChildFragmentManager(), fragment.getId()); / / get the navigator provider NavigatorProvider provider. = navController getNavigatorProvider (); // Add a custom Fragment navigator to provider.addNavigator(fragmentNavigator); NavGraph = initNavGraph(provider, fragmentNavigator); // Set the navigation graph navController.setgraph (navGraph); . / / at the bottom of the navigation Settings click event navView setOnNavigationItemSelectedListener (item - > {navController. Navigate (item, getItemId ()); return true; }); viewModel.name.observe(this, new Observer<String>() { @Override public void onChanged(String s) { text.setText(s); }}); } // Create navigation map manually, Private NavGraph initNavGraph(NavigatorProvider provider, FixFragmentNavigator fragmentNavigator) { NavGraph navGraph = new NavGraph(new NavGraphNavigator(provider)); / / with a custom navigator FragmentNavigator. To create a Destination 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); FragmentNavigator.Destination destination2 = fragmentNavigator.createDestination(); destination2.setId(R.id.navigation_dashboard); destination2.setClassName(DashboardFragment.class.getCanonicalName()); destination2.setLabel(getResources().getString(R.string.title_dashboard)); navGraph.addDestination(destination2); FragmentNavigator.Destination destination3 = fragmentNavigator.createDestination(); destination3.setId(R.id.navigation_notifications); destination3.setClassName(NotificationsFragment.class.getCanonicalName()); destination3.setLabel(getResources().getString(R.string.title_notifications)); navGraph.addDestination(destination3); navGraph.setStartDestination(R.id.navigation_home); return navGraph; } / * * * * fix: rewrite the return key events ComponentActivity. OnBackPressed - >... - > NavController. PopBackStack () * custom navigator, */ @override public void onBackPressed() {int currentId = navController.getCurrentDestination().getId(); int startId = navController.getGraph().getStartDestination(); // If the current destination is not HomeFragment, return to HomeFragment if (currentId! = startId) { navView.setSelectedItemId(startId); } else { finish(); }}}Copy the code
Reference:Android-Jetpack note-Navigation Fragment support reuse