如何正确地删除对话框片段?

对于 Dialog类中的 dismiss()方法,文档是这样说的:

取消此对话框,将其从屏幕上删除。可以调用此方法 请注意,不应重写此方法以执行 清除对话框,而是在 onStop()中实现。

在我的代码中,我所做的就是调用 getDialog().dismiss()来解除它。但我没有做任何其他事情,甚至没有使用 onStop()。因此,我正在询问如何正确地解除 DialogFragment,以避免任何内存泄漏等。.

160496 次浏览

您应该在 onPause()中解除 Dialog,以便重写它。

同样在解散之前,你可以检查 null并显示如下片段:

@Override
protected void onPause() {
super.onPause();
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}

关闭 DialogFragment的正确方法是使用 dismiss() 直接放在对话框碎片上


详情 : 对话片段的文档状态

对话框的控制(决定何时显示、隐藏、删除它)应该通过这里的 API 来完成,而不是通过对话框的直接调用。

因此,您不应该使用 getDialog().dismiss(),因为那将调用 dismiss()在对话框上。相反,您应该使用 DialogFragment 本身的 dismiss()方法:

公众无效解雇()

取消片段及其对话框。如果片段被添加到回堆栈中,那么将弹出直到并包括该条目的所有回堆栈状态。否则,将提交一个新的事务来删除该片段。

正如您所看到的,这不仅需要关闭对话框,而且还需要处理流程中涉及的片段事务。

只有在显式创建了需要手动清理的资源(关闭文件、关闭游标等)时,才需要使用 onStop。即使这样,我也会覆盖 DialogFragment 的 onStop,而不是底层 Dialog 的 onStop

我认为关闭 DialogFragment的一个更好的方法是:

Fragment prev = getSupportFragmentManager().findFragmentByTag("fragment_dialog");
if (prev != null) {
DialogFragment df = (DialogFragment) prev;
df.dismiss();
}

这样,你不必持有一个参考的 DialogFragment,可以关闭它从任何地方。

我对特雷尔的回答表示赞同,我只是想把这篇文章发给所有科特林的用户:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
(it as DialogFragment).dismiss()
}

科特林回答

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()

你为什么不试试只用这个代码:

dismiss();

如果您想单独关闭对话框片段。您可以简单地将这段代码放在您想要取消对话框的对话框片段中。

例如:

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});

这将关闭屏幕上显示的最近的对话框片段。

希望对你有帮助。

只需从您想要忽略的片段中调用 release ()即可。

imageView3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});

在其他的回答中也提到了官方文件(参考对话框片段) ,但是没有提到这里给出的例子:

void showDialog() {
mStackLevel++;


// DialogFragment.show() will take care of adding the fragment
// in a transaction.  We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);


// Create and show the dialog.
DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft, "dialog");
}

这将删除当前显示的任何对话框,创建一个新的 DialogFragment 并将其显示为堆栈上的一个新状态 弹出事务、当前 DialogFragment 及其对话框 将被销毁,并重新显示前一个(如有的话)。请注意 在这种情况下,DialogFragment 将负责弹出事务 对话的内容被单独解散。

为了满足我的需要,我把它改成:

FragmentManager manager = getSupportFragmentManager();
Fragment prev = manager.findFragmentByTag(TAG);
if (prev != null) {
manager.beginTransaction().remove(prev).commit();
}


MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);

我发现,当在导航图中使用 <fragment>标记(对于全屏对话框片段)定义片段时,对话框片段不会用 dismiss()命令解散。相反,我不得不打开后面的堆栈:

findNavController(getActivity(), R.id.nav_host_fragment).popBackStack();

但是,如果在导航图中使用 <dialog>标记定义了相同的对话框片段,则 dismiss()可以正常工作。

CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
dialog.dismiss();
}

添加到其他答案,当有一个全屏调用 dismiss()DialogFragment时,不会从片段回栈中弹出 DialogFragment。一个解决方案是对父活动调用 onBackPressed()

就像这样:

CustomDialogFragment.kt

closeButton.onClick {
requireActivity().onBackPressed()
}

考虑下面的示例代码片段,它演示了如何安全地删除对话框片段:

DialogFragment dialogFragment = new DialogFragment();


/**
* do something
*/


// Now you want to dismiss the dialog fragment
if (dialogFragment.getDialog() != null && dialogFragment.getDialog().isShowing())
{
// Dismiss the dialog
dialogFragment.dismiss();
}

编码愉快!

下面是一个简单的 AppCompatActivity 扩展函数,它关闭打开的对话框片段:

fun AppCompatActivity.whenDialogOpenDismiss(
tag: String
) {
supportFragmentManager.findFragmentByTag(tag)?.let {
if(it is DialogFragment) it.dismiss() }
}

当然你可以直接从任何活动中调用它。 如果你需要从一个片段调用它,只需对片段类使用相同的扩展函数即可