9 lines of code to let Fragment in your App say goodbye to overlapping

Update:
The official version of Support 24.0.0 and above has fixed the BUG that caused the overlap caused by the source code analysis in the previous article; so if you use a version above 24.0.0, under normal circumstances, you don’t need to consider the overlap problem anymore!
(PS: It is still recommended to read the "Supplement" section at the end of the article)

Solution via findFragmentByTag() & getFragments()

These two solutions are described in detail in my short book Fragment Full Analysis Series (1): The pits . You can check them yourself. There are not many introductions here. These two solutions are also the most common solutions. plan.

shortcoming:

  • It is cumbersome to use and has a large amount of code;
  • In the scenario of Fragment nesting, there will be problems with recovery. The reason is that after the page is restarted, before the initialization getChildFragmentManager()of the parent Fragment is completed, the child Fragment in the sub-stack is empty. Only after the initialization of the parent Fragment is completed, the child Fragment in the sub-stack to be obtained correctly.

Solution from the perspective of source code: save the Hidden state of Fragment by yourself

The following solution is what I thought of when I was perfecting the Fragmentation library .

The Fragmentation library has pushed a significant version 0.7 a few days ago, which should be considered relatively mature. If you use Fragment heavily or want to use a single Activity + multi-Fragment component architecture, it is strongly recommended to take a look; for various complex nesting, same-level In the usage scenario of Fragment, you don't have to worry about the overlap of Fragment, and at the same time greatly simplify the nesting logic of Fragment.

In the analysis of the previous short book , we know that the root cause of Fragment overlap is that FragmentState does not save the display state of Fragment, that is, mHiddenafter the page is restarted, the value is false by default, that is, the show state, so it leads to Fragment. overlapping.

Based on this reason, I thought it would be fine for us to maintain one manually mSupportHidden?
Look at the base class Fragment code below:

public class BaseFragment extends Fragment {
    
    
    private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
    
    
    ...
    if (savedInstanceState != null) {
    
    
        boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        if (isSupportHidden) {
    
    
            ft.hide(this);
        } else {
    
    
            ft.show(this);
        }
        ft.commit();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
    
    
        ...
        outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
    }
}

Yes, you read that right, as long as the above 9 lines of code! FragmentState does not help us save the Hidden state, so we save it ourselves. After the page restarts, we decide whether the Fragment is displayed or not!
The solution idea has changed, the Hidden state of the child Fragment is managed by the Activity/parent Fragment, and the Hidden state of the Fragment itself is managed by Fragment itself !

Advantages: No matter how deep the nested Fragment, Fragment of the same level, etc., all can work normally without overlapping!
Cons: None.

Replenish

Some small partners still have overlapping reactions. In fact, it is because there is no judgment when loading the root FragmentonCreate . When loading the root Fragment in a similar environment, the following judgment is required to avoid repeated loading of the same Fragment:
(PS: add, replacein the case, If the rollback stack is not added, no judgment will be made and no overlap will be caused; if the rollback stack is added, overlap will also be caused, so it is recommended to make a unified judgment)

public class MainActivity ... {
    
    

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        ...
        // 这里一定要在save为null时才加载Fragment,Fragment中onCreateView等生命周里加载根子Fragment同理
        // 因为在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠
        if(findFragmentByTag(rootFragmentTag) == null){
    
    
              // 正常情况下去 加载根Fragment 
        }
    }
}

at last

The final solution is used in my Fragmentation library . In the new Demo of imitating Zhihu, various complex scenes perform perfectly.

But this solution is really amazing. In my test, all kinds of situations are normally applicable, but I have never seen anyone mention this solution before, so if you find that this solution has bugs that I have not considered, please Tell me immediately!

The official version of Support 24.0.0 and above has used this method to fix the BUG from the bottom; if you are still using the version < 24.0.0, you still need these "9 lines of code"~

Finally, a little experience:
When encountering a problem, if we think about it from the source: Why did this problem happen? Analyzing the problem from the perspective of source code may give you a better idea to solve the problem!

Reprint: https://www.jianshu.com/p/c12a98a36b2b

Guess you like

Origin blog.csdn.net/gqg_guan/article/details/130085138