今天收到一个问题,检索日志后,看到了如下的错误提示:
AndroidRuntime: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:4)
AndroidRuntime: at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1)
AndroidRuntime: at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:12)
AndroidRuntime: at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:1)
AndroidRuntime: at android.support.v4.app.DialogFragment.show(DialogFragment.java:5)
而这个问题所在的原因是因为DialogFragment 在使用show()方法时出现了问题,即在显示fragment时执行如下的代码:
异常的原因是commit()方法在Activity的onSaveInstanceState()之后调用的,这样会出错,因为onSaveInstanceState方法是在该Activity即将被销毁前调用来保存Activity数据的,如果在保存完状态后再给它添加Fragment就会出错。
解决办法就是把commit()方法替换成 commitAllowingStateLoss()就行了,其效果是一样的,那么查看DialogFragment 源码并没有找到使用commitAllowingStateLoss()的show方法,那么应该怎么办呢?
思索一下:是否想到可以重写父类的show方法呢? 使用commitAllowingStateLoss() 来替换commit() 方法,然而,发现该方法使用了私有变量,这就尴尬了,咋办,立马又想到可以使用反射的技术,来修改父类的私有变量,来保证重写show方法后,其他的状态合法正常:
代码如下:
/**
* 重写父类show()方法
* 避免出现java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
*/
@Override
public void show(FragmentManager manager, String tag) {
try {
Class cls = this.getClass().getSuperclass();
if (cls == null) return;
Field mDismissed = cls.getDeclaredField("mDismissed");
Field mShownByMe = cls.getDeclaredField("mShownByMe");
mDismissed.setAccessible(true);
mShownByMe.setAccessible(true);
mDismissed.setBoolean(this, false);
mShownByMe.setBoolean(this, true);
} catch (Exception e) {
Log.e("DialogFragment", "show", e.fillInStackTrace());
}
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
经过测试,目前未发现其他问题,欢迎大家指出不合理的地方
补充一下,网上有人说,点home键后,onSaveInstanceState()方法在onPause()之前执行,而我测试的结果是,先执行onPause()方法,后执行onSaveInstanceState()方法。
————————————————
本文是转载的,以备自己查阅,原文链接:https://blog.csdn.net/baidu_28027209/article/details/79740209