【Android策略】Can not perform this action after onSaveInstanceState with DialogFragment
阿新 • • 發佈:2019-01-26
友盟錯誤詳情:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1323) at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1341) at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597) at android.app.BackStackRecord.commit(BackStackRecord.java:575) at android.app.DialogFragment.show(DialogFragment.java:230) at com.storm.durian.activity.MainActivity$MyHandler.handleMessage(MainActivity.java:670) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5282) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:810) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) at dalvik.system.NativeStart.main(Native Method)
根據錯誤,我們找到了相應的程式碼:
就是在handleMessage中做了如下操作:
問題就出在這:CheckInfoItem checkInfo = (CheckInfoItem) msg.obj; theLayout.checkInfo = checkInfo; SignDialogFragment dialog = SignDialogFragment.newInstance(checkInfo); dialog.show(theLayout.getFragmentManager(), "SignDialog");
1、因為我是在onResume方法中調取了簽到介面,然後拿到簽單資訊,彈出簽到視窗,因此可能導致該異常發生。
2、onSaveInstanceState方法是在該Activity即將被銷燬前呼叫,來儲存Activity資料的,如果在儲存玩狀態後再給它新增Fragment就會出錯
3、解決方法就是把commit()方法替換成 commitAllowingStateLoss()
api中是這麼解釋commitAllowingStateLoss()
4、但是我們呼叫的是DialogFragment的show方法,我們來看一下show方法的原始碼Like 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 void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
我們發現它是通過commit進行提交的,所以就會帶來java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState的風險
5、為了解決這個問題,我的處理方式是:
public void showCheckInDialog(CheckInfoItem checkInfo) {
SignDialogFragment dialog = SignDialogFragment.newInstance(checkInfo);
//這裡直接呼叫show方法會報java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
//因為show方法中是通過commit進行的提交(通過檢視原始碼)
//這裡為了修復這個問題,使用commitAllowingStateLoss()方法
//注意:DialogFragment是繼承自android.app.Fragment,這裡要注意同v4包中的Fragment區分,別調用串了
//DialogFragment有自己的好處,可能也會帶來別的問題
//dialog.show(getFragmentManager(), "SignDialog");
android.app.FragmentManager fm = getFragmentManager();
android.app.FragmentTransaction ft = fm.beginTransaction();
ft.add(dialog, "SignDialog");
ft.commitAllowingStateLoss();
}
這裡我們通過自己手動新增完成,解決這個問題。
6、有很多可能性會造成java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState,在stackoverflow中有很多這樣的案例,如果我的方法解決不了你的問題,你可以參考一下它們的
7、我發現解友盟上的這些bug還是挺費力的,不管是自己挖的坑還是別人挖的坑