Android: AlertDialogs и фрагменты - PullRequest
3 голосов
/ 07 декабря 2011

Я переключаю одно из своих приложений на фрагменты (от просто действий) и либо я что-то упускаю, либо они серьезно усложнили весь процесс показа AlertDialog.

Во-первых, вот что я пытаюсь сделать: показать один из нескольких диалогов с предупреждениями с положительной и отрицательной кнопками с методами обратного вызова, связанными с каждым дном. Диалог должен пережить (то есть: воссоздать) поворот экрана.

До: В прошлом все, что вам нужно было сделать, - это создать AlertDialog с соответствующими методами обратного вызова и т. Д. И показать его, и система позаботится обо всем, включая поворот экрана.

Теперь: если я создаю и показываю AlertDialog из моего фрагмента, он не воссоздается при повороте экрана и, согласно LogCat, теряет память во время уничтожения. Согласно новым документам для разработчиков по фрагментам, я должен использовать DialogFragment для создания AlertDialog, чтобы менеджер фрагментов мог обрабатывать такие вещи, как поворот экрана и т. Д. (См. Здесь: http://developer.android.com/reference/android/app/DialogFragment.html под заголовком «Диалог оповещения»). хорошо, однако, проблема в методах обратного вызова. В представленном примере они жестко закодированы в двух методах в Activity. У меня есть две проблемы с этим, я не хочу вовлекать активность в этот процесс, и мне нужны разные методы обратного вызова для разных создаваемых мной AlertDialog. Я действительно не хочу создавать разные классы с жестко закодированными обратными вызовами для каждого AlertDialog, который я буду создавать. Должен быть более простой способ, иначе это просто глупость :)

Другой способ поместить вещи ... фрагменты воссоздаются после поворота экрана менеджером фрагментов, используя любые «аргументы», которые были сохранены в процессе создания. Эти аргументы сохраняются в Bundle, однако я не могу сохранить метод обратного вызова внутри Bundle, поэтому менеджер фрагментов не может воссоздать фрагмент с переданным методом обратного вызова, только жестко закодированный, что означает, что мне нужны отдельные классы. с жестко закодированными методами обратного вызова для каждого типа AlertDialog я буду отображать ... это глупо или я просто что-то здесь упускаю?

Спасибо за любую помощь, Гарри

Ответы [ 2 ]

1 голос
/ 17 мая 2012

Вы можете использовать интерфейсы, чтобы немного убрать жестко закодированные обратные вызовы.

В следующем примере мой класс фрагмента диалога указывает интерфейс с именем Host. Действия, которые хотят использовать этот фрагмент, должны будут реализовать интерфейс MyAlertDialog.Host и иметь два метода, которые он определяет. Конечно, вместо общих имен onOptionOne и onOptionTwo вы можете использовать onReport, onRetry - что бы ни имело смысл для каждого предупреждения.

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 не ссылается на какие-либо конкретные действия. Когда действие решает использовать это диалоговое окно, оно должно выполнить свой контракт. Это, а не наоборот, где диалог будет связан с действиями и будет подключаться к ним.

0 голосов
/ 08 декабря 2011

Вызов setRetainInstance (true) заставит FragmentManager сохранить фактический экземпляр Fragment.Вместо того, чтобы разрушать и воссоздавать фрагмент, он просто передает тот же самый новый вид деятельности.

Главное, что нужно знать об использовании setRetainInstance (true), - это то, что один экземпляр Fragment может видеть несколько вызовов onCreateView () и onDestroyView () в течение времени жизни фрагмента, поскольку он связан с различными операциями.Так, если, например, вы зарегистрировали BroadcastReceiver в onCreateView () и отменили его регистрацию в onDestroy (), ваш код будет нормально работать с setRetainInstance (false), но не с setRetainInstance (true).

Edit - это не только этоответьте неправильно, но я обсуждаю смежную проблему !

Так что я заслуживаю всех отрицательных ответов, которые я получаю.:) Существует ошибка в setRetainInstance (true), которую можно исправить грубым взломом - вызовите getDialog (). SetDismissMessage (null) внутри onDestroyView () вашего DialogFragment, чтобы взломать его.

...