在 DialogFragment 上提交AllowingStateLoss

问题描述 投票:0回答:4

我在显示

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
变量,我如何访问这些变量来修改它们,就像它的父级那样。

android android-fragments android-dialogfragment dialogfragment
4个回答
55
投票

我认为防止将

IllegalStateException
扔到
DialogFragment
上可能会更好使用:

 YourDialogFragment dialogFragment = new YourDialogFragment();
 fragmentManager.beginTransaction().add(dialogFragment, YourDialogFragment.TAG_FRAGMENT).commitAllowingStateLoss();

而不是在

show()
上使用
DialogFragment


13
投票

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;
}

13
投票

起源对话框片段

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

获取

0
投票

聚会有点晚了,但希望它能在未来帮助其他人。 发生此问题的原因是 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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.