Recently, the project entered the stage of endless bug repair, and many problems really gave me a headache for a while, including the management of multiple fragments in a single Activity page. Maybe IT is because I know too little about fragments and have encountered many problems, so this article focuses on what kind of problems I have encountered and how to solve them. I hope to offer some help to those who have similar problems.
Modified on May 23rd, 5 days after I wrote this article, I changed the layout of the home page and put most of the content into the ViewStub for a delayed loading operation. The result is that onSaveInstanceState’s method of saving the Fragment is invalid. After each destruction, the Fragment data is still there, but the page is empty. After a day of continuous attempts, I finally found that the ViewStub does not have the problem of Fragment overlap – it is true that I have been pitted by myself.
-
Fragment click penetrate
The homepage of my current project is a MainActivity containing 5 fragments, and TAB switching can be done through hide&Show. There was a nasty problem at the beginning: clicking on the current Fragment page would redirect to another Fragment page. In particular, a click event occurred at the location of another Fragment page that should not be clicked. This problem is not 100% recurrent, and some models do not occur, and some are frequent. Finally saw this post has solved the problem – click through solution of fragments overlay] (blog.csdn.net/xieluoxixi/…). . The following content is referenced from this post:
This problem is actually a click event distribution problem. When multiple fragments are added to the Fragment stack, the click event of the Fragment at the bottom of the stack remains valid even after the Fragment at the top appears. There are three specific solutions, which can be viewed in the post.
In my project, I used the second option because I used fragments a lot. I added view.setClickable(true) globally to BaseFragment; The problem never resurfaced.
@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(this.getLayoutId(), container, false); rootView.setClickable(true); // Set the View's click property to true to block click propagation return super.onCreateView(inflater, container, savedInstanceState); } Copy the code
-
Fragment overlap (double shadow)
This is the opposite of the previous problem, where the interface doesn’t overlap, but the click events overlap. In this case, there is only interface overlap, but there is no problem with clicking (maybe because I have solved the previous problem, otherwise there will be problems).
The situation is that when the APP is abnormally destroyed and restarted, it may cause insufficient memory, or no processing after rotating the screen direction, etc. You can check “Do not Retain Activity” in developer mode, so that every time you return to the desktop and switch back to the APP, it will reload again to simulate the effect of running out of memory, so that it is easier to check whether the problem exists.
The cause of this problem is also easier to find, the solution is not difficult, you can search a lot of posts on the Internet. OnSaveInstanceState () is used to restore the Fragment after the screen is rotated. The reason for this problem is that the system will restore the Fragment by default using the state saved before the destruction. However, after the APP was destroyed and restarted, the Fragment was added again, causing the Fragment overlap.
But I saw some online posts, found no mention of a point, this question in the Activity of the root XML layout added android: fitsSystemWindows = “true” method, will not appear, at least for me. This problem has never occurred in my project before. One day, I changed the layout of the home page to immersion and removed this method, and the phenomenon of Fragment overlapping appeared. After tuning the problem later, I wondered why it hadn’t happened before, was it because of this line of code? So I found an older version and installed it on my phone, opened the Developer option — Do not Save Activity, and found that the problem did not appear. I’m not sure if this is a question of individual mobile phone, or set the android: fitsSystemWindows = “true” then I really don’t overlap. Hope to have an understanding of the friends informed.
Back to how to solve this problem. The simplest way to do this is to directly disallow the Activity to save the state when it is destroyed, comment out the contents of onSaveInstanceState(Bundle outState), and restart the Activity without resuming and overwriting it. But it’s too rough, and there’s no user experience at all. That in the project of course can not be such a one-size-fits-all, the following code to describe how I deal with:
-
In the onSaveInstanceState(Bundle outState) method on the home page of the MainActivity, determine all the current fragments and save the loaded fragments
@Override protected void onSaveInstanceState(Bundle outState) { /*fragment is not empty */ for (int i = 0; i < TAB_SIZE; i++) { // Check whether the fragment has been added to the Fragment Manager if(mFragmentList[i].isAdded() && mFragmentList[i] ! =null) { // Save the loaded FragmentgetSupportFragmentManager().putFragment(outState, mFragmentTags[i], mFragmentList[i]); }}// Pass in the value of the currently selected TAB and redirect to the TAB after destruction and restart outState.putInt(CURRENT_INDEX, mCurrentIndex); super.onSaveInstanceState(outState); } Copy the code
Here it is important to note that by getSupportFragmentManager () putFragment (); Before saving the Fragment as a Tag, ensure that the Fragment has been added to the FragmentManager. Otherwise, IllegalStateException appears: Fragment is not currently in the FragmentManager error.
-
Restore the saved Fragment in onCreate(Bundle savedInstanceState) :
@Override public void onCreate(Bundle savedInstanceState) { if(savedInstanceState ! =null) { /* Return null*/ if no fragment exists for (int i = 0; i < TAB_SIZE; i++) { Fragment fragment = getSupportFragmentManager().getFragment(savedInstanceState, mFragmentTags[i]); if(fragment ! =null) { mFragmentList[i] = fragment; } } mCurrentIndex = savedInstanceState.getInt(CURRENT_INDEX, INDEX_HOME); } initFragment(); initTab(); } Copy the code
When entering the onCreate function, check whether savedInstanceState is null and check whether the Fragment Tag exists step by step. If so, the Fragment is added to the list of the Fragment.
-
Initialize the fragments
This is the first step, but with the addition of the previous operations, the FragmentList that was empty is now not empty. So when initializing each Fragment, remember to check whether it already exists. If not, create a new object, otherwise you have already added the previously saved Fragment:
private void initFragment(a) { if (mFragmentList[0] = =null) { mFragmentList[0] = new xxFragment// The Fragment to be created; } if (mFragmentList[1] = =null) { mFragmentList[1] = new xxFragment } if (mFragmentList[2] = =null) { mFragmentList[2] = new xxFragment } if (mFragmentList[3] = =null) { mFragmentList[3] = new xxFragment } if (mFragmentList[4] = =null) { mFragmentList[4] = new xxFragment } } Copy the code
Fragment the Fragment to restore the Fragment, create the Fragment, and then follow the normal process. The overlap problem doesn’t arise anymore.
-