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