Android:AlertDialogs和Fragments

时间:2011-12-07 19:33:42

标签: android android-activity callback alertdialog android-fragments

我正在将我的一个应用程序切换到片段(仅来自活动),或者我完全错过了某些内容,或者他们在显示AlertDialog的整个过程中都非常复杂。

首先,这是我正在尝试做的事情:显示一个带有正负按钮的警告对话框,其中每个底部都有一个回调方法。对话需要生存(即:重新创建)一个屏幕旋转。

之前:在过去,您所要做的就是使用正确的回调方法等创建一个AlertDialog并显示它,系统会处理所有事情,包括屏幕旋转。

现在:如果我从片段创建并显示AlertDialog,则在屏幕旋转期间不会重新创建它,并且根据LogCat在销毁期间泄漏内存。根据关于片段的新开发人员文档,我应该使用DialogFragment来创建一个AlertDialog,以便片段管理器可以处理屏幕旋转等内容(请参阅此处:警告对话框标题下的http://developer.android.com/reference/android/app/DialogFragment.html)那很好但是,问题是回调方法。在提供的示例中,它们被硬编码为Activity中的两个方法。我有两个问题,我不想让这个过程涉及活动,我需要为我创建的不同AlertDialog提供不同的回调方法。我真的不想为我将要创建的每个AlertDialog创建带有硬编码回调的不同类。必须有一个更简单的方法,否则这只是愚蠢:)

片段管理器使用在创建过程中保存的任何“参数”在屏幕旋转后重新创建另一种放置...片段的方法。这些参数保存在Bundle中,但是,我无法在Bundle中保存回调方法,因此片段管理器无法使用传递的回调方法重新创建片段,只能使用硬编码方法,这意味着我需要单独的类使用每种类型的AlertDialog的硬编码回调方法,我将显示...这是愚蠢的还是我只是在这里遗漏了什么?

感谢您的帮助, 哈利

2 个答案:

答案 0 :(得分:1)

您可以使用接口来整理硬编码的回调。

在下面的示例中,我的对话框片段类指定了一个名为Host的接口。想要使用此片段的活动必须实现MyAlertDialog.Host接口并具有它定义的两种方法。当然,您可以使用onOptionOneonOptionTwo代替通用onReportonRetry名称 - 对每个警报都有意义。

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;

public class MyAlertDialog extends DialogFragment {

    /**
     * Host activities have to implement this interface to receive button click
     * callbacks.
     * 
     */
    public static interface Host {
        public void onOptionOne();

        public void onOptionTwo();
    }

    public static MyAlertDialog newInstance() {
        return new MyAlertDialog();
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                Host host;
                try {
                    host = (Host) getActivity();
                } catch (ClassCastException e) {
                    String name = getActivity().getClass().getName();
                    throw new RuntimeException("Class " +  name + " doesn't implement MyAlertDialog.Host interface");
                }

                if (which == DialogInterface.BUTTON_POSITIVE)
                    host.onOptionOne();
                if (which == DialogInterface.BUTTON_NEGATIVE)
                    host.onOptionTwo();
            }
        };

        return new AlertDialog.Builder(getActivity())
                .setMessage("Message here")
                .setPositiveButton("Option One", clickListener)
                .setNegativeButton("Option Two", clickListener)
                .create();
    }
}

这方面的好处是,MyAlertDialog没有提到任何具体的活动。当一个活动选择使用该对话框时,它必须实现其合同。而不是以其他方式,对话将与活动相结合,并将它们挂钩。

答案 1 :(得分:0)

调用setRetainInstance(true)将导致FragmentManager保存实际的Fragment实例。它不会破坏和重新创建片段,而是将相同的片段传递给新的Activity。

使用setRetainInstance(true)要注意的主要事情是,一个Fragment实例可能会在Fragment的生命周期中看到对onCreateView()和onDestroyView()的多次调用,因为它与不同的Activity相关联。如果是,例如你在onCreateView()中注册了一个BroadcastReceiver并在onDestroy()中注册了它,你的代码可以正常使用setRetainInstance(false),但不能使用setRetainInstance(true)。

编辑 - 这个答案不仅错误,而且我am in the discussion for the related issue

所以我应该得到所有的支持。 :) setRetainInstance(true)上有一个错误,你可以用一个严重的黑客修复 - 在你的DialogFragment的onDestroyView()中调用getDialog()。setDismissMessage(null)来破解它。