问题描述:
当手机进入黑屏的时候,APP蓝牙断开连接,APP收到蓝牙断开连接,通过EventBus方式调用commit方法让UI界面跳转到蓝牙连接界面,此时会报Can not perform this action after onSaveInstanceState:错误,且不会正常跳转到指定界面,从网上找到解决方法是:commitAllowingState()方法替换commit()方法,问题解决。
根据网上资料,总结如下,以便后续参考。
首先找到FragmentTransaction方法的实现类
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator
而FragmentTransaction类中的commit方法与commitAllowState调用如下:
public int commit() {
return commitInternal(false);
}
public int commitAllowingStateLoss() {
return commitInternal(true);
}
两个方法最终调用commitInternal方法,只是commit传入了false,另一个传入了true;
进入commitInternal方法:
int commitInternal(boolean allowStateLoss) {
if (mCommitted) {
throw new IllegalStateException("commit already called");
}
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new FastPrintWriter(logw, false, 1024);
dump(" ", null, pw, null);
pw.flush();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
在此方法中只有mManager.enqueueAction(this, allowStateLoss)代码用到了参数allowStateLoss,进入mManager.enqueueAction方法如下:
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
当调用commit时allowStateLoss为true,其会进入如下代码:
if (!allowStateLoss) {
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);
}
}
根据上面内容,只要mStateSaved为true就会报Can not perform this action after onSaveInstanceState错误,接下来分析,当手机黑屏的时候在哪里给mStateSaved设置成了true;
Parcelable saveAllState() {
...
execPendingActions();
mStateSaved = true;
mSavedNonConfig = null;
...
}
这个方法分别是在FragmentActivity的onSaveInstanceState()中被调用,而onSaveInstanceState()的调用时机是在onPause()之后onStop()之前,这样可以总结出来当Activity的onSaveInstanceState()方法调用之后如果调用了该Activity的FragmentTransaction的commit方法,就会抛出异常。
在使用中此处蓝牙断开连接,是通过EventBus来进行MainActivity的Fragment切换,由于在进入锁屏后会调用会调用onPause(), onSaveInstanceState(), onStop()方法,因此mStateSaved = true, 最终会报上述错误,修改为commitAllowingState()方法,问题解决。