1. Phenomenon
Use Navigation to jump between fragments. When switching with the bottom Tab effect, fragments will refresh every time. This effect is certainly not what you want, so it needs to be solved.
2. Cause
Cause of the problem: when the Navigation group jumps to another Fragment, the Navigation () method uses the ft.replace() method in the source code
And mfragmentmanager getFragments(). Size () gets bigger and bigger.
Based on this, you should recreate a Fragment every time, not just refresh the page.
Since it's a new Fragment, it's not just a refresh problem. This is created through the full class name, and the analysis is likely to create a Fragment through reflection
Call create Fragment code. Through source code tracing, it is really reflection that creates a new source code Fragment public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) { try { Class<? extends Fragment> cls = loadFragmentClass(classLoader, className); return cls.getConstructor().newInstance(); }
3. Online solutions
Solution: copy the NavHostFragment and FragmentNavigator classes into the project, modify the navitgate() method in FragmentNavigator, and modify the path of import FragmentNavigator in NavHostFragment.
public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) { // ... ellipsis if(mFragmentManager.getFragments().size()>0){ ft.hide(mFragmentManager.getFragments().get(mFragmentManager.getFragments().size()-1)); ft.add(mContainerId, frag); }else { ft.replace(mContainerId, frag); } // ft.replace(mContainerId, frag); ft.setPrimaryNavigationFragment(frag); // ... ellipsis }
This is the online source code, but direct use has no effect
The reason for the problem is that it is only changed here, or a new Fragment will be created every time, which can not achieve the expected effect
Modify again
···
if(mFragmentManager.getFragments().size()>0){
ft.hide(mFragmentManager.getFragments().get(mFragmentManager.getFragments().size()-1));
ft.add(mContainerId, frag);
}else {
ft.replace(mContainerId, frag);
}
//This place should be revised according to the specific situation
//Here, first find out whether it has been loaded. If there is no add, if it has been loaded, it will be directly displayed, and then hide others
if(mFragmentManager.getFragments().size()>0){ // TODO
ft.hide(mFragmentManager.getFragments().get(mFragmentManager.getFragments().size()-1));
boolean hasAdd =false;
for (int i = 0; i < mFragmentManager.getFragments().size(); i++) {
Fragment f = mFragmentManager.getFragments().get(i);
if(f!=null&& f.getClass().getName().equals(className)){
hasAdd = true;
}else{
ft.hide (mFragmentManager.getFragments().get(i));
}
}
if(!hasAdd){
ft.add(mContainerId, frag);
}
// ft.show(frag);
ft.replace(mContainerId, frag); }else { ft.replace(mContainerId, frag); }
···
After this location is changed, it still can't achieve the effect. That is, the source code above will create a new Fragment every time
Modify the part of the new source code
Fragment tempFrag = null; for (int i = 0; i < mFragmentManager.getFragments().size(); i++) { Fragment f = mFragmentManager.getFragments().get(i); if(f!=null&& f.getClass().getName().equals(className)){ tempFrag = f; } } final Fragment frag ; if(tempFrag!=null){ frag = tempFrag; }else{ frag = instantiateFragment(mContext, mFragmentManager, className, args); } frag.setArguments(args);
This line of code will first determine whether this fragment has been add ed before
If you add, you don't need to create a new one. Just display it
Overall process
Copy the NavHostFragment and FragmentNavigator classes into the project, modify the navitgate() method in FragmentNavigator, and modify the path of import FragmentNavigator in NavHostFragment
The copied file NavHostFragment is referenced in xml
<androidx.fragment.app.FragmentContainerView android:id="@+id/my_nav_host_fragment" android:name="com.androideasy.navigate.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:navGraph="@navigation/nav_graph_main" />
This temporarily realizes the switching effect
But I personally feel very bad. It is not recommended.
The modified file will be released to the personal Git and will not be released for the time being
contact information
Q group: 960244875 welcome to exchange and rest
Email: AndroidEasy@126.com