有点晚参加派对,但希望将来能帮到其他人。
出现这个问题的原因是在Activity处于最多停止状态时调用了DialogFragment.show()方法,通常是因为我们开发者试图在API调用失败或类似情况下显示对话框,并且用户将应用程序置于后台,导致在Activity停止时调用了DialogFragment.show()方法。
为了解决这个问题,我们可以做一些非常简单的事情,创建一个持有对话框实例的LiveData,然后让Activity/Fragment观察该LiveData,如果有值,就显示对话框。
现在这样做是有效的,因为LiveData只在生命周期至少处于started状态时向观察者发送事件,所以当Activity/Fragment至少处于started状态时,对话框肯定会被显示。
根据LiveData.observe的文档说明:
将给定的观察者添加到给定所有者的观察者列表中。事件在主线程上分发。如果LiveData已经设置了数据,它将传递给观察者。
只有当所有者处于Lifecycle.State.STARTED或Lifecycle.State.RESUMED状态(活动状态)时,观察者才会收到事件。
代码示例如下:
在你的Fragment/Activity中创建一个LiveData -
private val dialogLiveData = MutableLiveData<DialogFragment?>()
下面我们将观察LiveData -
片段 -
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialogLiveData.observe(viewLifecycleOwner) {
if (it?.isAdded?.not() == true) {
it.show(childFragmentManager, "dialog")
}
}
}
活动 -
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dialogLiveData.observe(this) {
if (it?.isAdded?.not() == true) {
it.show(supportFragmentManager, "dialog")
}
}
}
现在当我们想要显示对话框时,我们只需要这样做 -
fun showDialog() {
dialogLiveData.value = DialogFragment()
}
然后当我们想要关闭对话框时,我们将这样做 -
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
}
}
注意:最好将LiveData保留在ViewModel内部,否则DialogFragment的实例可能会在屏幕旋转时丢失。
show(FragmentManage, String)
时,可以忽略mDismissed
和mShownByMe
。我不能说这样做完全安全。当mShownByMe
为false
且mDismissed
默认为false
时,会有一些内部处理mDismissed
的情况。但是忽略它们似乎并不会对内部处理产生影响。 - BakaWaii