屏幕关闭时 DialogFragment IllegalStateException
DialogFragment IllegalStateException when screen goes off
首先,我已经阅读了数十个 SO 问题并阅读了 Alex Lockwood 撰写的关于 IllegalStateException
与片段事务相关的问题的优秀 post:https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html - tl;dr 我已经完成作业了
但是我在任何地方都找不到的是 IllegalStateException
屏幕关闭时的问题,我们正在尝试提交片段事务 - 在我的例子中显示 DialogFragment
。
我的应用程序中真正发生的事情是对其他 activity 结果作出反应,然后显示 DialogFragment
。 正如许多 SO 用户所建议的那样,我没有显示来自 onActivityResult
的对话框,而是来自 onPostResume
的对话框(我也尝试过使用 onResumeFragments
) 简化代码看起来像这样
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Timber.i("${this::class.java.simpleName} onActivityResult")
activityResult = ActivityResult(this::class, requestCode, resultCode, data)
}
override fun onPostResume() {
super.onPostResume()
Timber.i("${this::class.java.simpleName} onPostResume")
activityResult?.let { ActivityResultRepository.resultsSubject.onNext(it) }
}
override fun onResumeFragments() {
super.onResumeFragments()
Timber.i("${this::class.java.simpleName} onResumeFragments")
}
我无法在我的设备 (Mate 20 pro) 或模拟器上重现异常,但我收到了我应用程序用户的崩溃报告(0.5% 的用户受影响)
我的假设是,我的应用试图在屏幕关闭后显示一个对话框。屏幕关闭是导致调用 onSaveInstanceState
方法的任意事件,它可以在我的 onPostResume
方法之前调用。 但这只是我的假设!,也许还有其他原因导致异常
有没有人遇到过类似的问题并且设法解决了?我知道我可以使用 commitAllowingStateLoss
但首先 - DialogFragment
的 show
方法不允许这样做,必须使用 FragmentManager
手动显示对话框(不要知道是否有任何影响),其次 commitAllowingStateLoss
通常是一件坏事
我正在添加崩溃报告,尽管每个人都已经在某个地方看到了它:)
Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2053)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2079)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:678)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:632)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)
Activity class 有方法 isFinishing()
、link to method。您可以轻松查看:
if (!this.isFinishing)
loadingDialog.show()
上面的示例是打开普通对话框,但您可以将其与 DialogFragment 一起使用。
这种情况经常发生。 Activity 未处于显示对话框的正确状态。你可以用这个来保护自己:
if (!isFinishing() && !isDestroyed()) {
dialog.show();
}
我已经接受了@MatPag 的回答,虽然我最终得到了不同的解决方案,所以我发布了它,也许它会对某人有所帮助
在我的场景中,我不关心 savedInstanceState - 当 Android 重新创建它时显示 activity 的初始状态对我来说完全没问题,所以我将 null 传递给父级 onCreate方法:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(null)
}
稍后,在显示对话框时,我捕获了可能抛出的 IllegalStateException,我为此创建了辅助方法:
private fun DialogFragment.showAllowingStateLoss(manager: FragmentManager?, tag: String) {
try {
this.show(manager, tag)
} catch (e: IllegalStateException) {
// no-op
}
}
首先,我已经阅读了数十个 SO 问题并阅读了 Alex Lockwood 撰写的关于 IllegalStateException
与片段事务相关的问题的优秀 post:https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html - tl;dr 我已经完成作业了
但是我在任何地方都找不到的是 IllegalStateException
屏幕关闭时的问题,我们正在尝试提交片段事务 - 在我的例子中显示 DialogFragment
。
我的应用程序中真正发生的事情是对其他 activity 结果作出反应,然后显示 DialogFragment
。 正如许多 SO 用户所建议的那样,我没有显示来自 onActivityResult
的对话框,而是来自 onPostResume
的对话框(我也尝试过使用 onResumeFragments
) 简化代码看起来像这样
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Timber.i("${this::class.java.simpleName} onActivityResult")
activityResult = ActivityResult(this::class, requestCode, resultCode, data)
}
override fun onPostResume() {
super.onPostResume()
Timber.i("${this::class.java.simpleName} onPostResume")
activityResult?.let { ActivityResultRepository.resultsSubject.onNext(it) }
}
override fun onResumeFragments() {
super.onResumeFragments()
Timber.i("${this::class.java.simpleName} onResumeFragments")
}
我无法在我的设备 (Mate 20 pro) 或模拟器上重现异常,但我收到了我应用程序用户的崩溃报告(0.5% 的用户受影响)
我的假设是,我的应用试图在屏幕关闭后显示一个对话框。屏幕关闭是导致调用 onSaveInstanceState
方法的任意事件,它可以在我的 onPostResume
方法之前调用。 但这只是我的假设!,也许还有其他原因导致异常
有没有人遇到过类似的问题并且设法解决了?我知道我可以使用 commitAllowingStateLoss
但首先 - DialogFragment
的 show
方法不允许这样做,必须使用 FragmentManager
手动显示对话框(不要知道是否有任何影响),其次 commitAllowingStateLoss
通常是一件坏事
我正在添加崩溃报告,尽管每个人都已经在某个地方看到了它:)
Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2053)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2079)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:678)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:632)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)
Activity class 有方法 isFinishing()
、link to method。您可以轻松查看:
if (!this.isFinishing)
loadingDialog.show()
上面的示例是打开普通对话框,但您可以将其与 DialogFragment 一起使用。
这种情况经常发生。 Activity 未处于显示对话框的正确状态。你可以用这个来保护自己:
if (!isFinishing() && !isDestroyed()) {
dialog.show();
}
我已经接受了@MatPag 的回答,虽然我最终得到了不同的解决方案,所以我发布了它,也许它会对某人有所帮助
在我的场景中,我不关心 savedInstanceState - 当 Android 重新创建它时显示 activity 的初始状态对我来说完全没问题,所以我将 null 传递给父级 onCreate方法:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(null)
}
稍后,在显示对话框时,我捕获了可能抛出的 IllegalStateException,我为此创建了辅助方法:
private fun DialogFragment.showAllowingStateLoss(manager: FragmentManager?, tag: String) {
try {
this.show(manager, tag)
} catch (e: IllegalStateException) {
// no-op
}
}