Fragment的状态保存与恢复导致的重叠

作者: cuixbo | 来源:发表于2017-07-14 18:13 被阅读287次

    我们在开发过程中有时会遇到Fragment内容重叠的情况,其具体原因可以参考这篇文章:从源码角度分析,为什么会发生Fragment重叠?

    简单说就是Support 24.0.0之前的Fragment在onSaveInstanceState()时并没有保存mHidden状态,导致Activity在重新创建后恢复Fragment时其被新创建的恢复的fragment都是默认为show状态的,引起了内容重叠.

    其实上面的文章中也提到了解决办法,不过对于Activity中的处理方式没有进行具体说明,下面我讲列出我的示例代码说明一下:

    Fragment的修改:
    public class BaseFragment extends Fragment {
        private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";
        protected Context mContext;
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            log();
            //fragment恢复后,恢复到原来的show,hide状态
            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.commitAllowingStateLoss();
            }
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            log();
            outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
        }
    }
    
    Activity中对于Fragment的创建于恢复使用:
    public class MainActivity extends BaseActivity {
    
        private BottomNavigationBar bottomNavigationBar;
        private FragmentManager fragmentManager;
        private final static String TAG_HOT = "热映";
        private final static String TAG_EXPLORER = "找片";
        private final static String TAG_MINE = "我的";
        private final static String[] TAGS = new String[]{"热映", "找片", "我的"};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
            initListener();
            bottomNavigationBar.selectTab(0);
        }
    
        private void initView() {
            fragmentManager = getFragmentManager();
            bottomNavigationBar = (BottomNavigationBar) findViewById(R.id.bottom_navigation_bar);
            bottomNavigationBar
                    .addItem(new BottomNavigationItem(R.drawable.ic_hot_normal, "热映"))
                    .addItem(new BottomNavigationItem(R.drawable.ic_explore_normal, "找片"))
                    .addItem(new BottomNavigationItem(R.drawable.ic_mine_normal, "我的"))
                    .setMode(BottomNavigationBar.MODE_FIXED)
                    .initialise();
        }
    
        private void initListener() {
            bottomNavigationBar.setTabSelectedListener(new BottomNavigationBar.OnTabSelectedListener() {
                @Override
                public void onTabSelected(int position) {
                    FragmentTransaction transaction = fragmentManager.beginTransaction();
                    Fragment fragment = fragmentManager.findFragmentByTag(TAGS[position]);
                    if (fragment == null) {
                        switch (position) {
                            case 0:
                                fragment = new HotMovieFragment();
                                break;
                            case 1:
                                fragment = new ExploreMovieFragment();
                                break;
                            case 2:
                                fragment = new MineFragment();
                                break;
                        }
                        if (fragment != null) {
                            transaction.add(R.id.fl_fragment_container, fragment, TAGS[position]);
                        }
                    } else {
                        transaction.show(fragment);
                    }
                    transaction.commitAllowingStateLoss();
                }
    
                @Override
                public void onTabUnselected(int position) {
                    FragmentTransaction transaction = fragmentManager.beginTransaction();
                    Fragment fragment = fragmentManager.findFragmentByTag(TAGS[position]);
                    if (fragment != null) {
                        transaction.hide(fragment);
                        transaction.commitAllowingStateLoss();
                    }
                }
    
                @Override
                public void onTabReselected(int position) {
    
                }
            });
        }
    }
    

    需要注意的是:
    transaction.add(R.id.fl_fragment_container, fragment, tag);
    上面这行代码要慎用,因为Activity重建后,之前的Fragment会被系统重新恢复,如果Activity重建后你在Activity中再次add的话就会可能出现重叠的情况.这种情况下就不用再去创建了,而是应该找到系统给我们恢复了的那些Fragment,
    Fragment fragment = fragmentManager.findFragmentByTag(tag);
    用上面这行代码就可以找到我们恢复的fragment,如果为空我们再去创建新的.

    关于Activity,Fragment重建的个人理解:

    所谓Activity重建,其实应该是系统保存了Activity的状态,系统给重新创建了个新的Activity实例并且恢复了之前保存的销毁的那个Activity的状态,使得Activity像是被重启了一样,新创建的其实是一个全新的Activity,其成员变量等都是新实例的.同样,Fragment也是如此,系统会恢复之前保存的销毁了的Fragemnt的状态,而重新创建Fragment,这些重新创建的Fragment可以通过FragmentManager的findFragmentByTag()方法来获取到.

    至此,我们就明白了Fragment的保存与恢复了吧.

    相关文章

      网友评论

      本文标题:Fragment的状态保存与恢复导致的重叠

      本文链接:https://www.haomeiwen.com/subject/dndohxtx.html