我在显示
IllegalStateException
时有一个 DialogFragment
:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
我知道为什么会发生,但我想通过覆盖 DialogFragment show
函数来使用
commitAllowingStateLoss显示对话框:
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit(); //replace it by commitAllowingStateLoss
}
但我无法访问
mDismissed
和 mShownByMe
变量,我如何访问这些变量来修改它们,就像它的父级那样。
我认为防止将
IllegalStateException
扔到 DialogFragment
上可能会更好使用:
YourDialogFragment dialogFragment = new YourDialogFragment();
fragmentManager.beginTransaction().add(dialogFragment, YourDialogFragment.TAG_FRAGMENT).commitAllowingStateLoss();
而不是在
show()
上使用 DialogFragment
。
commitAllowingStateLoss 的解决方案适用于您的 DialogFragment 没有要保存的状态,否则它们将像函数名称所示那样丢失。但我认为在大多数情况下我们需要保存状态,这是 DialogFragment 的主要好处:Android 会重新创建它并自动维护其状态。
更好的解决方案是检查重新创建过程是否完成,如果没有完成,则返回给调用者,调用者可以是 Activity 或 FragmentActivity,它应该调用 mark 它并稍后在 onPostResume() 或 onResumeFragments() 中再次调用 show 函数) 回调,我们可以确保重新创建所有片段。
这是来自 DialogFragment 子类的重写 show():
public boolean show(FragmentManager fragmentManager) {
if (fragmentManager.isStateSaved()) return false;
show(fragmentManager, tagName);
return true;
}
起源对话框片段
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit(); //replace it by commitAllowingStateLoss
}
我不知道
mDismissed
,mShownByMe
变量的用途,所以如果重写DialogFragment的show(FragmentManager, String)
方法应该会更好,并且它对我来说效果很好
override fun show(manager: FragmentManager?, tag: String?) {
if (manager?.isDestroyed == false && !manager.isStateSaved) {
super.show(manager, tag)
}
}
isStateSaved
可从 appcompat >= 26.0.0 或 androidx 获取
聚会有点晚了,但希望它能在未来帮助其他人。 发生此问题的原因是 DialogFragment.show() 在 Activity 至少处于停止状态时被调用,这通常是由于我们开发人员试图显示对话框作为对 API 调用失败或类似情况的响应,并且用户将应用程序置于后台,这会导致 DialogFragment.show() 在活动停止时被调用。
为了解决这个问题,我们可以做一些非常简单的事情,我们创建一个 LiveData 来保存对话框的实例,然后,我们让活动/片段观察 LiveData,如果有一个值,我们就显示对话框。 现在这将起作用,因为 LiveData 仅在生命周期大于启动时才向观察者发送事件,因此当 Activity/Fragment 至少处于启动状态时,保证会显示对话框。
从文档到 LiveData.observe -
将给定观察者添加到给定所有者生命周期内的观察者列表中。事件在主线程上调度。如果LiveData已经有数据集,则会将其传递给观察者。 仅当所有者处于 Lifecycle.State.STARTED 或 Lifecycle.State.RESUMED 状态(活动)时,观察者才会接收事件。
这就是代码的样子 -
在您的片段/活动中创建一个 LiveData -
private val dialogLiveData = MutableLiveData<DialogFragment>()
接下来我们将观察 LiveData -
碎片-
dialogLiveData.observe(viewLifecycleOwner) {
if (it.isAdded.not()) {
it.show(childFragmentManager, "dialog")
}
}
活动-
private val dialogLiveData = MutableLiveData<DialogFragment>()
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
dialogLiveData.observe(this) {
if (it.isAdded.not()) {
it.show(supportFragmentManager, "dialog")
}
}
}
现在,当我们想要关闭对话框时,这就是我们要做的 -
fun dismissDialog() {
val dialog = dialogLiveData.value
dialog?.let {
if (dialog.isAdded) {
if (dialog.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED).not()) {
dialogLiveData.value?.dismissAllowingStateLoss()
} else {
dialogLiveData.value?.dismiss()
}
}
dialogLiveData.value = null
}
}