当前位置: 移动技术网 > IT编程>开发语言>Java > Can not perform this action after onSaveInstanceState

Can not perform this action after onSaveInstanceState

2020年09月20日  | 移动技术网IT编程  | 我要评论
在Android开发中,遇到如下异常:Process: com.xxx, PID: 28227 java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=88, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to

在Android开发中,遇到如下异常:

Process: com.xxx, PID: 28227 java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=88, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.xxx.MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 
 Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
       at androidx.fragment.app.FragmentManager.checkStateLoss(FragmentManager.java:1766)
        at androidx.fragment.app.FragmentManager.enqueueAction(FragmentManager.java:1806)
        at androidx.fragment.app.BackStackRecord.commitInternal(BackStackRecord.java:324)
        at androidx.fragment.app.BackStackRecord.commit(BackStackRecord.java:289)
        at androidx.fragment.app.DialogFragment.show(DialogFragment.java:253)
        at com.xxx.DialFragment$15.hasPermission(DialFragment.java:1224)
        at com.xxx..BaseActivity.onRequestPermissionsResult(BaseActivity.java:146)
        at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6728)
        at android.app.Activity.dispatchActivityResult(Activity.java:6606)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:3748)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:3795)
        at android.app.ActivityThread.access$1400(ActivityThread.java:168)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1428)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:150)
        at android.app.ActivityThread.main(ActivityThread.java:5639)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:799)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:689)

 出现这种异常的原因是因为fragment事物执行commit,它的操作状态可能已经丢失,这时Android framework会抛出一个异常,解决办法如下:

重写show方法:

@Override
public void show(@NonNull FragmentManager manager, @Nullable String tag) {
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commitAllowingStateLoss();
}

看一下相关源码:

 /**
     * Like {@link #commit} but allows the commit to be executed after an
     * activity's state is saved.  This is dangerous because the commit can
     * be lost if the activity needs to later be restored from its state, so
     * this should only be used for cases where it is okay for the UI state
     * to change unexpectedly on the user.
     */
    public abstract int commitAllowingStateLoss();
/**
     * Display the dialog, adding the fragment to the given FragmentManager.  This
     * is a convenience for explicitly creating a transaction, adding the
     * fragment to it with the given tag, and committing it.  This does
     * <em>not</em> add the transaction to the back stack.  When the fragment
     * is dismissed, a new transaction will be executed to remove it from
     * the activity.
     * @param manager The FragmentManager this fragment will be added to.
     * @param tag The tag for this fragment, as per
     * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
     */
    public void show(FragmentManager manager, String tag) {
        mDismissed = false;
        mShownByMe = true;
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commit();
    }
/**
     * Schedules a commit of this transaction.  The commit does
     * not happen immediately; it will be scheduled as work on the main thread
     * to be done the next time that thread is ready.
     *
     * <p class="note">A transaction can only be committed with this method
     * prior to its containing activity saving its state.  If the commit is
     * attempted after that point, an exception will be thrown.  This is
     * because the state after the commit can be lost if the activity needs to
     * be restored from its state.  See {@link #commitAllowingStateLoss()} for
     * situations where it may be okay to lose the commit.</p>
     * 
     * @return Returns the identifier of this transaction's back stack entry,
     * if {@link #addToBackStack(String)} had been called.  Otherwise, returns
     * a negative number.
     */
    public abstract int commit();
   public int commit() {
        return commitInternal(false);
    }

    public int commitAllowingStateLoss() {
        return commitInternal(true);
    }
    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", null, pw, null);
        }
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }
    public void enqueueAction(Runnable action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<Runnable>();
            }
            mPendingActions.add(action);
            if (mPendingActions.size() == 1) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
    }
    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);
        }
    }

来看一下mStateSaved什么情况为True

    Parcelable saveAllState() {
        ...
        if (HONEYCOMB) {
            // As of Honeycomb, we save state after pausing.  Prior to that
            // it is before pausing.  With fragments this is an issue, since
            // there are many things you may do after pausing but before
            // stopping that change the fragment state.  For those older
            // devices, we will not at this point say that we have saved
            // the state, so we will allow them to continue doing fragment
            // transactions.  This retains the same semantics as Honeycomb,
            // though you do have the risk of losing the very most recent state
            // if the process is killed...  we'll live with that.
            mStateSaved = true;
        }
        ...
    }



static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;

说明:当系统版本号大于等于11时,当执行了saveAllState的方法时,mStateSaved 就会为true。而这个saveAllState()方法是在系统保存状态后执行的。

本文地址:https://blog.csdn.net/ljt2724960661/article/details/108657154

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网