欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Can not perform this action after onSaveInstanceState

程序员文章站 2022-03-09 16:08:44
在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

相关标签: Android基础