美文网首页
Crash:Can not perform this actio

Crash:Can not perform this actio

作者: 比目鱼26 | 来源:发表于2017-02-15 11:47 被阅读0次

堆栈信息

bug0.png

版本分布

bug1.png

机型

bug2.png

问题分析

0,Activity->onBackPressed

public void onBackPressed() {
        if (!mFragments.popBackStackImmediate()) {
            finish();
        }
    }

1,FragmentManager->popBackStackImmediate

/**
     * Like {@link #popBackStack()}, but performs the operation immediately
     * inside of the call.  This is like calling {@link #executePendingTransactions()}
     * afterwards.
     * @return Returns true if there was something popped, else false.
     */
    public abstract boolean popBackStackImmediate();

2,FragmentManagerImpl->popBackStackImmediate

@Override
    public boolean popBackStackImmediate() {
        checkStateLoss();
        executePendingTransactions();
        return popBackStackState(mHost.getHandler(), null, -1, 0);
    }

3,FragmentManagerImpl->checkStateLoss

private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        if (mNoTransactionsBecause != null) {
            throw new IllegalStateException(
                    "Can not perform this action inside of " + mNoTransactionsBecause);
        }
    }

NOTE:崩溃的原因就是mStateSaved=true抛出了IllegalStateException,需要找到mStateSaved在哪些地方被赋值为true

4,FragmentManagerImpl->saveAllState

Parcelable saveAllState() {
        // Make sure all pending operations have now been executed to get
        // our state update-to-date.
        execPendingActions();

        mStateSaved = true;//赋值
        .....
}

mSateSaved只会在saveAllState()中被重新赋值为true,继续跟进saveAllState()在哪些场景下会被调用

5, Activity->onSaveInstanceState

    protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        Parcelable p = mFragments.saveAllState();//在这被调用
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

可以得出初步的结论是当Activity调用onSaveInstanceState,间接改变了FragmentManagerImpl中mStateSaved的值,onBackPressed()被调用时会导致FragmentManagerImpl检查mStateSaved值,为true就抛出异常导致崩溃

6,关于onSaveInstanceState

这一篇介绍了onSaveInstanceState的调用时机,所以分析可能的操作步骤是,Activity->Home(或者电源键)->回Activity->onBackPressed。
当用户回道回到Activity时,生命周期必然会经过onResume,mStateSaved状态会重置成false,onBackPressed就不会引起崩溃,这就是矛盾。

解决方案

反射FragmentActivity中的FragmentController对象,调用noteStateNotSaved方法,修改mStateSaved的值为false。
这样的做的原因是:用户点击back键的目的是退出界面或者dismiss当前界面的dialog(或者其他浮层),对于前者不用考虑状态保存的问题,对于后者Activity的生命周期会重新onResume,不会影响Fragment状态保存。

@Override
    public void onBackPressed() {
        fixBug();
        super.onBackPressed();
    }
private void fixBug() {
        try {
            Class clz = BaseActivity.class;
            while (clz != FragmentActivity.class) {
                clz = clz.getSuperclass();
            }
            Field field = clz.getDeclaredField("mFragments");
            field.setAccessible(true);
            Object object = field.get(this);//获取mFragments对象
            Class<?> fieldClazz = object.getClass();
            Method method = fieldClazz.getMethod("noteStateNotSaved");
            method.setAccessible(true);
            method.invoke(object);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

相关文章

网友评论

      本文标题:Crash:Can not perform this actio

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