应用程序处于后台时正确关闭 DialogFragment 的方法

79

我开始使用DialogFragment,因为它们在屏幕方向改变等情况下运行良好。但是我遇到了一个严重的问题。

我有一个AsyncTask,它显示进度DialogFragment并在onPostExecute中解除事件绑定。一切工作正常,但当应用程序在后台时(例如按Home键后),onPostExecute发生时会出现错误,Dialog将无法解除 - "Can not perform this action after onSaveInstanceState"。普通对话框完全正常。但不适用于FragmentDialog。

所以我想知道,在应用程序处于后台时解除DialogFragment的正确方法是什么?我并没有真正使用过Fragments,所以我认为我只是缺少某些东西。


请参考这里,使用暂停的处理程序来解决AsyncTask在暂停时引发IllegalStateException的问题。 - PJL
5个回答

168

DialogFragment 有一个名为 dismissAllowingStateLoss() 的方法。


16
只有当使用 show(FragmentManager, tag) 时才有效,而不是使用 show(FragmentTransaction, tag),因为在 dismissInternal 中的 popBackStack 调用了 enqueueAction(..., allowStateLoss=false),尽管我们要求允许状态丢失。这在框架和支持版本中都会发生。 - TWiStErRob
对我来说不起作用 - thecr0w

10
这是我所做的(df == dialogFragment)
确保您以这种方式调用对话框:
df.show(getFragmentManager(), "DialogFragment_FLAG");

当您想要关闭对话框时,请进行以下检查:
if (df.isResumed()){
  df.dismiss();
}
return;

请确保您在片段的onResume()方法中(而不是df)具有以下内容。
@Override
public void onResume(){
  Fragment f = getFragmentManager().findFragmentByTag("DialogFragment_FLAG");
  if (f != null) {
    DialogFragment df = (DialogFragment) f;
    df.dismiss();
  }
  super.onResume();
}   

如果对话框可见,它将被关闭。如果对话框不可见,则在片段变为可见(onResume)后将关闭对话框。


当用户返回时,这总是会关闭片段,如果他们还没有阅读对话框,只是在显示后立即离开应用程序,该怎么办? - TWiStErRob
dismiss() already removes the dialog fragment internally. Source code: getFragmentManager().beginTransaction(); ft.remove(this); - Ryan Amaral

3
这是我为实现您想要的而必须执行的操作: 我有一个片段活动,在其中显示了一个名为fragment_RedemptionPayment的对话框片段,该片段在顶部全局声明。以下代码将在活动进入后台并回到前台时解除DialogFragment的显示。
     @Override
        public void onResume() {
            super.onResume();        
            if(fragment_RedemptionPayment.isVisible()){
                fragment_RedemptionPayment.dismiss();
            }
}

2

另一种在调用dismiss之前检查状态的新方法如下:

if(!dialog.isStateSaved){
    dialog.dismiss()
} else {
    //Change the UI to suit your functionality
}

通过这种方式,检查状态是否已保存,基本上在暂停和调用onSaveInstanceState时进行。

对于Java,您可以使用isStateSaved()


0
一个可能有效的解决方案是在你的DialogFragment中设置Fragment.setRetainInstance(true),但这并不是最好的解决方法。
有时我注意到我必须排队我的对话框操作,让框架先恢复状态。如果你可以获取当前的Looper (Activity.getMainLooper()) 并将其包装在一个Handler中,你可以尝试通过在该队列上发布一个可运行项来将你的解散传递到队列的后面。
我经常使用一个单独的fragment,它retaininstance(true),有一个ResultReceiver。所以我把那个结果接收器传给我的工作,然后在它的onReceive中处理回调(通常作为其他接收器的路由器)。但如果你正在使用异步任务,这可能需要更多的工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接