Fragment页面加载混乱 视图重叠问题 如何优雅的解决

[Vio.wang 崇尚开源 欢迎点评]
本来是打算将此问题记载到问题反馈中,但是感觉涉及到的面偏大,就单写一篇吧。
其实这也算的上是一个比较常见的问题了,APP被回收之后,重新回到前台时,页面Activity会被重新加载,其中必然涉及到了onSaveInstanceState()及 onRestoreInstanceState()两个方法,都懂得,大家都是资深猿。
刚开始发现这个问题其实也蛮诧异的,这也算是google没考虑到的吧,扯远了。网上关于这个问题有两个解决方案,如下:
(1)重写onSaveInstanceState方法,将调用父类的方法给干掉。此招毒辣,釜底抽薪,不失优雅。

    @Override
    protected void onSaveInstanceState(Bundle outState) {
//        super.onSaveInstanceState(outState);
        outState.putInt("mLastIndex", mLastIndex);

    }

让我们看看父类中是如何进行处理的,又为何需要把它给干掉。

   /**
     * Save all appropriate fragment state.
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
    }

由于Activity继承了FragmentActivity,FragmentActivity默认就执行次方法,在页面被回收时,保存了所有已加载的fragment状态。
再看看其onCreate()

if (savedInstanceState != null) {
   Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
   mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
}
mFragments.dispatchCreate();

在FragmentActivity的onCreate中又默认恢复了当前保存的fragment.
这里就可以看出fragment加载混乱的根本原因了,FragmentActivity帮我们管理了当前的fragment,而我们在自己的Activity中没有做判断就直接添加视图,所以很显然会出现问题。
或许你会说,我做了判断啊,那我们来看看第二种解决方法:
(2)第二种方法便是找到我们的getSupportFragmentManager中的已添加的fragment。
首先在add Fragment时调用以下方法,给Fragment添加一个tag(tag建议给一个fragmentTags的数组)。

 public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment,
            @Nullable String tag);

然后在onCreate中判断savedInstanceState != null 时根据tag在getSupportFragmentManager中重新拿到fragment,如:

aroundFragment = (AroundFragment) manager.findFragmentByTag(fragmentTags[0]);

这样也可以解决问题,有人说不行,请多尝试一二。
(3)这种方法,说起来也是把我坑苦了,由于项目需要集成融云,直接复用了融云的会话列表UI。集成过RC的人可能知道,RC的会话列表加载方式是通过动态Uri的方式加载。这样的话,第一种方式就不能用了,与RC冲突,第二种方式同样也不理想,也出了问题,页面被回收之后,重新加载回来会话列表为空,呃。。。森森的受伤了。。。
于是,便研究起了getSupportFragmentManager的管理策略,我的想法就是讲栈中所有的fragment清空,重新加载一遍,应该就不会有问题了。
那么,怎么清空栈呢?��http://stackoverflow.com/questions/6186433/clear-back-stack-using-fragments
在这里记录一下:
清空栈:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

推出某fragment及以上的fragment

FragmentManager.popBackStack(XX.class.getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE)

然后,我们同样需要在判断if (savedInstanceState != null) {}中将所有的fragment置空:

@Override
    protected void init(Bundle savedInstanceState) {

        setContentView(R.layout.activity_main);

            FragmentManager manager = getSupportFragmentManager();

        if (savedInstanceState != null) {
            mLastIndex = savedInstanceState.getInt("mLastIndex", 0);

            //fragmentmanager将栈中所有在ConversationListFragment之上的fragment推出
//            manager.popBackStack(ConversationListFragment.class.getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
            for (int i = 0; i < manager.getBackStackEntryCount(); ++i) {
                manager.popBackStack();
            }

            conversationListFragment = null;
            ......
 }

问题至此解决。。。

你可能感兴趣的:(Android之开发总结篇)