Android中在app被系统释放后,重新回到前台时,重建Activity出现Fragment重叠现象

android 开发中Frgment应用场景非常广泛,应用Fragment是必须使用FragmentActivity,有时候会出现这样一种情况,在应用退到后台后,系统会在内存不足时将应用回收掉,再次启动应用会出现Activity中的Fragment重叠现象,其实出现问题的原因是这样的,在回收应用回收前FragmentActivity会调用onSaveInstanceState(Bundle outState) 方法,保存当前的Fragment的状态。

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mPendingFragmentActivityResults.size() > 0) {
            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);

            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
            }
            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
        }
    }

我们再次打开应用FragmentActivity会重新创建走onCreate方法。在FragmentActivity的onCreate方法如果不处理,会恢复之前保存的Fragment状态,同时我们又在onCreate中重新初始化了Fragment,这样就会出现Fragment两次被添加到Activity的情况。

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        super.onCreate(savedInstanceState);

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

            // Check if there are any pending onActivityResult calls to descendent Fragments.
            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
                mNextCandidateRequestIndex =
                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
                if (requestCodes == null || fragmentWhos == null ||
                            requestCodes.length != fragmentWhos.length) {
                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
                } else {
                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
                    for (int i = 0; i < requestCodes.length; i++) {
                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
                    }
                }
            }
        }

        if (mPendingFragmentActivityResults == null) {
            mPendingFragmentActivityResults = new SparseArrayCompat<>();
            mNextCandidateRequestIndex = 0;
        }

        mFragments.dispatchCreate();
    }

通过上面的简单分析就可基本上对问题的解决就有一个大致的解决思路啦,下面我提供了自己认为的解决方案

方案一:
在onCreate方法方法中判断savedInstanceState变量是否为空,如果不为空就是认为是重建的,我们给savedInstanceState.putParcelable(FRAGMENTS_TAG, null);这样系统就不会恢复savedInstanceState保存的Fragment了,也就不会出现重复添加的问题了。这处理的问题比较简单,不易出现错误,但是重建后的状态会回收之前的状态不一样,会影响用户体验。

 protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            //activity 回收恢复时,重新生成 fragment。
            savedInstanceState.putParcelable(FRAGMENTS_TAG, null);
        }
        super.onCreate(savedInstanceState);
     
 }

方案二:
我同样要进行判断在onCreate方法方法中判断savedInstanceState变量是否为空,如果不为空就认为是重建的,不执行Fragment的创建工作,为空的情况才执行Fragment的创建工作。使用种方案会使重建后和重建前的效果一样,用户体验好,但是对于比较复杂的Fragment可能会增加错误的风险。

protected void onCreate(@Nullable Bundle savedInstanceState) {

        if (savedInstanceState == null) {
            intFragment();
        }
}

方案三:
就是在回收之前不对状态进行保存,我们重写onSaveInstanceState 并且不调用Fragment的onSaveInstanceState方法。用这样方案的确可以解决上面的问题,但是这样会让onSaveInstanceState 方法完全失去意义,就保存不了回收之前的任何信息了。

 @Override
    protected void onSaveInstanceState(Bundle outState) {
//        super.onSaveInstanceState(outState);
    }

以上的我认为的三种可以行的解决方案,应该还有更好的解决方法等着我去发现,如果后期有发现新的方案和有改进方法我还会进行更新。

你可能感兴趣的:(android)