Android DialogFragment vs Dialog

244

Google zaleca używanie DialogFragmentzamiast zwykłego Dialogza pomocą Fragments API, ale absurdalne jest używanie izolowanego DialogFragmentprostego pola z komunikatem potwierdzającym Tak-Nie. Jaka jest najlepsza praktyka w tym przypadku?

skayred
źródło
5
W skrócie, między innymi, proste Dialoglub AlertDialog.Builder::create()::show()utworzy okno dialogowe, które zniknie po obróceniu ekranu.
user1032613

Odpowiedzi:

83

Tak, użyj DialogFragmenti onCreateDialogmożesz po prostu użyć kreatora AlertDialog, aby utworzyć proste za AlertDialogpomocą przycisków potwierdzenia Tak / Nie. W ogóle niezbyt dużo kodu.

Jeśli chodzi o obsługę zdarzeń w twoim fragmencie, byłyby na to różne sposoby, ale po prostu definiuję komunikat Handlerw moim Fragment, przekazuję go do DialogFragmentjego konstruktora, a następnie przekazuję wiadomości z powrotem do modułu obsługi mojego fragmentu jako odpowiedni dla różnych zdarzeń kliknięcia. Znów różne sposoby na zrobienie tego, ale dla mnie działają następujące.

W oknie dialogowym przytrzymaj komunikat i utwórz go w konstruktorze:

private Message okMessage;
...
okMessage = handler.obtainMessage(MY_MSG_WHAT, MY_MSG_OK);

Zaimplementuj onClickListenerw oknie dialogowym, a następnie odpowiednio wywołaj moduł obsługi:

public void onClick(.....
    if (which == DialogInterface.BUTTON_POSITIVE) {
        final Message toSend = Message.obtain(okMessage);
        toSend.sendToTarget();
    }
 }

Edytować

I jak w przypadku Messageprzesyłki, możesz ją zapisać onSaveInstanceStatei przywrócić

outState.putParcelable("okMessage", okMessage);

Następnie w onCreate

if (savedInstanceState != null) {
    okMessage = savedInstanceState.getParcelable("okMessage");
}
PJL
źródło
4
Problem nie jest okMessage - problem jest okMessage, targetktóry będzie zerowy, jeśli załadujesz go z pakietu. Jeśli cel komunikatu jest pusty i użyjesz go sendToTarget, otrzymasz wyjątek NullPointerException - nie dlatego, że komunikat jest pusty, ale dlatego, że jego celem jest.
hrnt
2
Jakie zalety używania DialogFragment zamiast Dialog?
Raphael Petegrosso,
80
Zaletą korzystania z DialogFragment jest to, że cały cykl życia okna dialogowego będzie obsługiwany za Ciebie. Nigdy więcej nie pojawi się błąd „wyciekło okno dialogowe ...”. Przejdź do DialogFragment i zapomnij Dialogi.
Snicolas,
6
Myślę, że zamiast przekazywania okMessage przez konstruktor należy użyć setArguments () i getArguments ().
pjv
1
Cóż, dość łatwo korzystam z Konstruktora użytkowników i zarządzam aktywnością za pomocą tego Androida: configChanges = "locale | keyboardHidden | orientacja | screenSize" i nie widzę żadnych problemów w aplikacjach ...
Renetik
67

Możesz tworzyć ogólne podklasy DialogFragment, takie jak YesNoDialog i OkDialog, i przekazywać tytuł i wiadomość, jeśli często używasz okien dialogowych w swojej aplikacji.

public class YesNoDialog extends DialogFragment
{
    public static final String ARG_TITLE = "YesNoDialog.Title";
    public static final String ARG_MESSAGE = "YesNoDialog.Message";

    public YesNoDialog()
    {

    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        Bundle args = getArguments();
        String title = args.getString(ARG_TITLE);
        String message = args.getString(ARG_MESSAGE);

        return new AlertDialog.Builder(getActivity())
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, null);
                }
            })
            .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, null);
                }
            })
            .create();
    }
}

Następnie zadzwoń, używając:

    DialogFragment dialog = new YesNoDialog();
    Bundle args = new Bundle();
    args.putString(YesNoDialog.ARG_TITLE, title);
    args.putString(YesNoDialog.ARG_MESSAGE, message);
    dialog.setArguments(args);
    dialog.setTargetFragment(this, YES_NO_CALL);
    dialog.show(getFragmentManager(), "tag");

I obsłuż wynik onActivityResult.

Ashishduh
źródło
Tak, DialogFragment obsługuje dla Ciebie wszystkie zdarzenia cyklu życia.
ashishduh
1
Myślę, że tak nie jest, ponieważ po rotacji stary Dialog nadal istnieje i nadal przypisuje się do starego nieistniejącego fragmentu (dialog.setTargetFragment (this, YES_NO_CALL);), więc po rotacji getTargetFragment (). OnActivityResult nie działa
Malachiasz
7
jakie są YES_NO_CALL, getFragmentManager()i onActivityResult?
msysmilu,
2
YES_NO_CALLto niestandardowy int, który jest kodem żądania. getFragmentManager()pobiera menedżera fragmentów dla działania i onActivityResult()jest metodą wywołania zwrotnego cyklu życia fragmentu.
ashishduh
3
Zamień getFragmentManager () na getSupportFragmentManager ();
Avinash Verma
33

Użyj DialogFragment zamiast AlertDialog:


  • Od czasu wprowadzenia interfejsu API na poziomie 13 :

    ShowDialog metodę z aktywności jest niezalecane . Wywołanie okna dialogowego w innym miejscu w kodzie nie jest wskazane, ponieważ będziesz musiał samodzielnie zarządzać oknem dialogowym (np. Zmiana orientacji).

  • Różnica DialogFragment - AlertDialog

    Czy są tak bardzo różni? Od referencji Androida dotyczących DialogFragment :

    DialogFragment to fragment, który wyświetla okno dialogowe unoszące się nad oknem działania. Ten fragment zawiera obiekt Dialog, który wyświetla odpowiednio w zależności od stanu fragmentu. Kontrola oknie (przy podejmowaniu decyzji, aby pokazać, ukryć, zwalnia go) powinno odbywać się za pośrednictwem interfejsu API tutaj , a nie z bezpośrednich połączeń w oknie dialogowym.

  • Inne notatki

    • Fragmenty są naturalną ewolucją w systemie Android ze względu na różnorodność urządzeń o różnych rozmiarach ekranu.
    • DialogFragments and Fragments są udostępniane w bibliotece wsparcia, dzięki czemu klasa jest użyteczna we wszystkich aktualnie używanych wersjach Androida.
Tobrun
źródło
28

Poleciłbym użyć DialogFragment.

Oczywiście utworzenie z nim okna dialogowego „Tak / Nie” jest dość skomplikowane, biorąc pod uwagę, że powinno to być dość proste zadanie, ale utworzenie podobnego okna dialogowego Dialogjest zaskakująco skomplikowane.

(Cykl życia działania komplikuje sprawę - musisz pozwolić Activityzarządzać cyklem życia okna dialogowego - i nie ma możliwości przekazania parametrów niestandardowych, np. Niestandardowego komunikatu, Activity.showDialogjeśli używasz poziomów API poniżej 8)

Zaletą jest to, że zazwyczaj łatwo można zbudować własną abstrakcję DialogFragment.

hrnt
źródło
Jak poradzisz sobie z oddzwanianiem w oknie dialogowym alertu (tak, nie)?
Aleksiej Zacharow
Najprostszym sposobem byłoby zaimplementowanie metody w działaniu hostingu, która przyjmuje Stringparametr. Na przykład, gdy użytkownik kliknie „Tak”, okno dialogowe wywołuje metodę działania z parametrem „zgoda”. Parametry te są określone podczas wyświetlania okna dialogowego, na przykład AskDialog.ask („Czy zgadzasz się na te warunki?”, „Zgadzasz się”, „nie zgadzam się”);
hrnt
5
Ale potrzebuję wywołania zwrotnego wewnątrz fragmentu, a nie aktywności. Mogę użyć setTargetFragment i przesłać go do interfejsu. Ale to jest piekło.
Aleksiej Zacharow
Można również pobrać fragment docelowej poprzez ustawienie znacznika do celu i przy użyciu FragmentManager„s findFragmentByTag. Ale tak, wymaga sporo kodu.
hrnt
@AlexeyZakharov Wiem, że to około 5 lat spóźnienia, ale możesz zdać Fragment this i mieć Activity extendsswój Interface. Ostrożnie wątkując, możesz odskakiwać wywołania interfejsu, gdy niekoniecznie chcesz je mieć, jeśli twoja współbieżność nie jest w ryzach. Nie jestem jednak pewien, co to robi z pamięcią i spaghetti z zależnością od koła, czy ktoś inny chciałby się do niego włączyć? Inną opcją jest Message/, Handlerale nadal możesz mieć problemy z współbieżnością.
tricknology
8

Ogólny AlertDialogFragment ze wzorem konstruktora

W moim projekcie wykorzystałem AlertDialog.Builderjuż dużo, zanim dowiedziałem się, że to problematyczne. Nie chciałem jednak zmieniać tak dużo kodu nigdzie w mojej aplikacji. Dodatkowo, tak naprawdę jestem fanem przechodząc OnClickListenersjako anonimowych klas, gdzie są one potrzebne (czyli podczas używania setPositiveButton(), setNegativeButton()itd.) Zamiast realizować tysiące metod wywołania zwrotnego do komunikowania się między fragmentem dialogowym i fragment uchwytu, który może w moim zdaniem prowadzi do bardzo zagmatwanego i złożonego kodu. Zwłaszcza jeśli masz wiele różnych okien dialogowych w jednym fragmencie, a następnie musisz rozróżnić w implementacjach wywołania zwrotnego, pomiędzy którymi okno dialogowe jest aktualnie wyświetlane.

Dlatego połączyłem różne podejścia, aby stworzyć ogólną AlertDialogFragmentklasę pomocnika, której można używać dokładnie tak, jak AlertDialog :


ROZWIĄZANIE

( PROSZĘ PAMIĘTAĆ, że używam wyrażeń lambda Java 8 w moim kodzie, więc może być konieczna zmiana części kodu, jeśli jeszcze nie używasz wyrażeń lambda ).

/**
 * Helper class for dialog fragments to show a {@link AlertDialog}. It can be used almost exactly
 * like a {@link AlertDialog.Builder}
 * <p />
 * Creation Date: 22.03.16
 *
 * @author felix, http://flx-apps.com/
 */
public class AlertDialogFragment extends DialogFragment {
    protected FragmentActivity activity;
    protected Bundle args;
    protected String tag = AlertDialogFragment.class.getSimpleName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activity = getActivity();
        args = getArguments();
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = setDialogDefaults(new AlertDialog.Builder(getActivity())).create();

        if (args.containsKey("gravity")) {
            dialog.getWindow().getAttributes().gravity = args.getInt("gravity");
        }

        dialog.setOnShowListener(d -> {
            if (dialog != null && dialog.findViewById((android.R.id.message)) != null) {
                ((TextView) dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
            }
        });
        return dialog;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);

        if (args.containsKey("onDismissListener")) {
            Parcelable onDismissListener = args.getParcelable("onDismissListener");
            if (onDismissListener != null && onDismissListener instanceof ParcelableOnDismissListener) {
                ((ParcelableOnDismissListener) onDismissListener).onDismiss(this);
            }
        }
    }

    /**
     * Sets default dialog properties by arguments which were set using {@link #builder(FragmentActivity)}
     */
    protected AlertDialog.Builder setDialogDefaults(AlertDialog.Builder builder) {
        args = getArguments();
        activity = getActivity();

        if (args.containsKey("title")) {
            builder.setTitle(args.getCharSequence("title"));
        }

        if (args.containsKey("message")) {
            CharSequence message = args.getCharSequence("message");
            builder.setMessage(message);
        }

        if (args.containsKey("viewId")) {
            builder.setView(getActivity().getLayoutInflater().inflate(args.getInt("viewId"), null));
        }

        if (args.containsKey("positiveButtonText")) {
            builder.setPositiveButton(args.getCharSequence("positiveButtonText"), (dialog, which) -> {
                onButtonClicked("positiveButtonListener", which);
            });
        }

        if (args.containsKey("negativeButtonText")) {
            builder.setNegativeButton(args.getCharSequence("negativeButtonText"), (dialog, which) -> {
                onButtonClicked("negativeButtonListener", which);
            });
        }

        if (args.containsKey("neutralButtonText")) {
            builder.setNeutralButton(args.getCharSequence("neutralButtonText"), (dialog, which) -> {
                onButtonClicked("neutralButtonListener", which);
            });
        }

        if (args.containsKey("items")) {
            builder.setItems(args.getStringArray("items"), (dialog, which) -> {
                onButtonClicked("itemClickListener", which);
            });
        }

        // @formatter:off
        // FIXME this a pretty hacky workaround: we don't want to show the dialog if onClickListener of one of the dialog's button click listener were lost
        //       the problem is, that there is no (known) solution for parceling a OnClickListener in the long term (only for state changes like orientation change,
        //       but not if the Activity was completely lost)
        if (
                (args.getParcelable("positiveButtonListener") != null && !(args.getParcelable("positiveButtonListener") instanceof ParcelableOnClickListener)) ||
                (args.getParcelable("negativeButtonListener") != null && !(args.getParcelable("negativeButtonListener") instanceof ParcelableOnClickListener)) ||
                (args.getParcelable("neutralButtonListener") != null && !(args.getParcelable("neutralButtonListener") instanceof ParcelableOnClickListener)) ||
                (args.getParcelable("itemClickListener") != null && !(args.getParcelable("itemClickListener") instanceof ParcelableOnClickListener))
        ) {
            new DebugMessage("Forgot onClickListener. Needs to be dismissed.")
                    .logLevel(DebugMessage.LogLevel.VERBOSE)
                    .show();
            try {
                dismissAllowingStateLoss();
            } catch (NullPointerException | IllegalStateException ignored) {}
        }
        // @formatter:on

        return builder;
    }

    public interface OnDismissListener {
        void onDismiss(AlertDialogFragment dialogFragment);
    }

    public interface OnClickListener {
        void onClick(AlertDialogFragment dialogFragment, int which);
    }

    protected void onButtonClicked(String buttonKey, int which) {
        ParcelableOnClickListener parcelableOnClickListener = getArguments().getParcelable(buttonKey);
        if (parcelableOnClickListener != null) {
            parcelableOnClickListener.onClick(this, which);
        }
    }

    // region Convenience Builder Pattern class almost similar to AlertDialog.Builder
    // =============================================================================================

    public AlertDialogFragment builder(FragmentActivity activity) {
        this.activity = activity;
        this.args = new Bundle();
        return this;
    }

    public AlertDialogFragment addArguments(Bundle bundle) {
        args.putAll(bundle);
        return this;
    }

    public AlertDialogFragment setTitle(int titleStringId) {
        return setTitle(activity.getString(titleStringId));
    }

    public AlertDialogFragment setTitle(CharSequence title) {
        args.putCharSequence("title", title);
        return this;
    }

    public AlertDialogFragment setMessage(int messageStringId) {
        return setMessage(activity.getString(messageStringId));
    }

    public AlertDialogFragment setMessage(CharSequence message) {
        args.putCharSequence("message", message);
        return this;
    }

    public AlertDialogFragment setPositiveButton(int textStringId, OnClickListener onClickListener) {
        return setPositiveButton(activity.getString(textStringId), onClickListener);
    }

    public AlertDialogFragment setPositiveButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
        args.putCharSequence("positiveButtonText", text);
        args.putParcelable("positiveButtonListener", createParcelableOnClickListener(onClickListener));
        return this;
    }

    public AlertDialogFragment setNegativeButton(int textStringId, AlertDialogFragment.OnClickListener onClickListener) {
        return setNegativeButton(activity.getString(textStringId), onClickListener);
    }

    public AlertDialogFragment setNegativeButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
        args.putCharSequence("negativeButtonText", text);
        args.putParcelable("negativeButtonListener", createParcelableOnClickListener(onClickListener));
        return this;
    }

    public AlertDialogFragment setNeutralButton(int textStringId, AlertDialogFragment.OnClickListener onClickListener) {
        return setNeutralButton(activity.getString(textStringId), onClickListener);
    }

    public AlertDialogFragment setNeutralButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
        args.putCharSequence("neutralButtonText", text);
        args.putParcelable("neutralButtonListener", createParcelableOnClickListener(onClickListener));
        return this;
    }

    public AlertDialogFragment setOnDismissListener(OnDismissListener onDismissListener) {
        if (onDismissListener == null) {
            return this;
        }

        Parcelable p = new ParcelableOnDismissListener() {
            @Override
            public void onDismiss(AlertDialogFragment dialogFragment) {
                onDismissListener.onDismiss(dialogFragment);
            }
        };
        args.putParcelable("onDismissListener", p);
        return this;
    }

    public AlertDialogFragment setItems(String[] items, AlertDialogFragment.OnClickListener onClickListener) {
        args.putStringArray("items", items);
        args.putParcelable("itemClickListener", createParcelableOnClickListener(onClickListener));
        return this;
    }

    public AlertDialogFragment setView(int viewId) {
        args.putInt("viewId", viewId);
        return this;
    }

    public AlertDialogFragment setGravity(int gravity) {
        args.putInt("gravity", gravity);
        return this;
    }

    public AlertDialogFragment setTag(String tag) {
        this.tag = tag;
        return this;
    }

    public AlertDialogFragment create() {
        setArguments(args);
        return AlertDialogFragment.this;
    }

    public AlertDialogFragment show() {
        create();
        try {
            super.show(activity.getSupportFragmentManager(), tag);
        }
        catch (IllegalStateException e1) {

            /**
             * this whole part is used in order to attempt to show the dialog if an
             * {@link IllegalStateException} was thrown (it's kinda comparable to
             * {@link FragmentTransaction#commitAllowingStateLoss()} 
             * So you can remove all those dirty hacks if you are sure that you are always
             * properly showing dialogs in the right moments
             */

            new DebugMessage("got IllegalStateException attempting to show dialog. trying to hack around.")
                    .logLevel(DebugMessage.LogLevel.WARN)
                    .exception(e1)
                    .show();

            try {
                Field mShownByMe = DialogFragment.class.getDeclaredField("mShownByMe");
                mShownByMe.setAccessible(true);
                mShownByMe.set(this, true);
                Field mDismissed = DialogFragment.class.getDeclaredField("mDismissed");
                mDismissed.setAccessible(true);
                mDismissed.set(this, false);
            }
            catch (Exception e2) {
                new DebugMessage("error while showing dialog")
                        .exception(e2)
                        .logLevel(DebugMessage.LogLevel.ERROR)
                        .show();
            }
            FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
            transaction.add(this, tag);
            transaction.commitAllowingStateLoss(); // FIXME hacky and unpredictable workaround
        }
        return AlertDialogFragment.this;
    }

    @Override
    public int show(FragmentTransaction transaction, String tag) {
        throw new NoSuchMethodError("Please use AlertDialogFragment.show()!");
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        throw new NoSuchMethodError("Please use AlertDialogFragment.show()!");
    }

    protected ParcelableOnClickListener createParcelableOnClickListener(AlertDialogFragment.OnClickListener onClickListener) {
        if (onClickListener == null) {
            return null;
        }

        return new ParcelableOnClickListener() {
            @Override
            public void onClick(AlertDialogFragment dialogFragment, int which) {
                onClickListener.onClick(dialogFragment, which);
            }
        };
    }

    /**
     * Parcelable OnClickListener (can be remembered on screen rotation)
     */
    public abstract static class ParcelableOnClickListener extends ResultReceiver implements AlertDialogFragment.OnClickListener {
        public static final Creator<ResultReceiver> CREATOR = ResultReceiver.CREATOR;

        ParcelableOnClickListener() {
            super(null);
        }

        @Override
        public abstract void onClick(AlertDialogFragment dialogFragment, int which);
    }

    /**
     * Parcelable OnDismissListener (can be remembered on screen rotation)
     */
    public abstract static class ParcelableOnDismissListener extends ResultReceiver implements AlertDialogFragment.OnDismissListener {
        public static final Creator<ResultReceiver> CREATOR = ResultReceiver.CREATOR;

        ParcelableOnDismissListener() {
            super(null);
        }

        @Override
        public abstract void onDismiss(AlertDialogFragment dialogFragment);
    }


    // =============================================================================================
    // endregion
}

STOSOWANIE

// showing a normal alert dialog with state loss on configuration changes (like device rotation)
new AlertDialog.Builder(getActivity())
        .setTitle("Are you sure? (1)")
        .setMessage("Do you really want to do this?")
        .setPositiveButton("Yes", (dialog, which) -> Toast.makeText(getContext(), "Yes clicked", Toast.LENGTH_SHORT).show())
        .setNegativeButton("Cancel", null)
        .show();

// showing a dialog fragment using the helper class with no state loss on configuration changes
new AlertDialogFragment.builder(getActivity())
        .setTitle("Are you sure? (2)")
        .setMessage("Do you really want to do this?")
        .setPositiveButton("Yes", (dialog, which) -> Toast.makeText(getContext(), "Yes clicked", Toast.LENGTH_SHORT).show())
        .setNegativeButton("Cancel", null)
        .show();

Zamieszczam to tutaj nie tylko po to, by podzielić się moim rozwiązaniem, ale także dlatego, że chciałem zapytać was ludzi o opinię: czy takie podejście jest do pewnego stopnia uzasadnione czy problematyczne?

flxapps
źródło
3
To bardzo interesujący pomysł, ale nie sądzę, żeby projekt API działał. Jeśli przekażesz OnClickListener do setPositiveButton (), gdy urządzenie zostanie obrócone, a fragment zostanie odtworzony z argumentów pakietu, OnClickListeners nie zostanie poprawnie odtworzony z działki Parcelable. Podstawową kwestią jest to, że nie można odtworzyć detektora podczas rotacji, ale wymaga tego interfejs API (który wymaga interfejsów). Chciałbym, żeby tak nie było (bo podoba mi się ten pomysł).
Xargs
1
Fajny pomysł, ale jak mówi @Xargs, nie działa. Przekazywane nasłuchiwania nie są odtwarzane poprawnie po obróceniu.
Graham Borland,
Moje wyniki są takie, że faktycznie działa on po obróceniu i wznowieniu do aplikacji (na przykład po przejściu do ekranu głównego), ale nie po przywróceniu aktywności po jej całkowitym zniszczeniu (wtedy OnClickListeners są rzeczywiście tracone). (Testowane na Androidzie 4.4.4 i Androidzie 5.1.1)
flxapps
Nie przetestowałem tej dokładnej implementacji, ale z tego, co przetestowałem, słuchacz paczkowy przekazany do pakietu fragmentów jest poprawnie wywoływany podczas odtwarzania. Nie mam pojęcia dlaczego, ale wydaje się, że działa.
Saad Farooq,
@flxapps, w przypadku widoku niestandardowego, w jaki sposób można uzyskać widoki potomne i zmienić ich właściwości lub zastosować detektory? W swojej klasie nie zwracasz żadnej instancji okna dialogowego, a to może spowodować wyjątek, jeśli ktoś spróbuje uzyskać widoki dziecka
Zubair Rehman
5

Czy mogę zasugerować trochę uproszczenia odpowiedzi @ ashishduh:

public class AlertDialogFragment extends DialogFragment {
public static final String ARG_TITLE = "AlertDialog.Title";
public static final String ARG_MESSAGE = "AlertDialog.Message";

public static void showAlert(String title, String message, Fragment targetFragment) {
    DialogFragment dialog = new AlertDialogFragment();
    Bundle args = new Bundle();
    args.putString(ARG_TITLE, title);
    args.putString(ARG_MESSAGE, message);
    dialog.setArguments(args);
    dialog.setTargetFragment(targetFragment, 0);
    dialog.show(targetFragment.getFragmentManager(), "tag");
}

public AlertDialogFragment() {}

@NonNull
@Override
public AlertDialog onCreateDialog(Bundle savedInstanceState)
{
    Bundle args = getArguments();
    String title = args.getString(ARG_TITLE, "");
    String message = args.getString(ARG_MESSAGE, "");

    return new AlertDialog.Builder(getActivity())
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, null);
                }
            })
            .create();
}

Eliminuje to potrzebę zaznajomienia użytkownika (klasy) z elementami wewnętrznymi komponentu i sprawia, że ​​korzystanie z niego jest naprawdę proste:

AlertDialogFragment.showAlert(title, message, this);

PS W moim przypadku potrzebowałem prostego okna dialogowego z ostrzeżeniem, więc to właśnie stworzyłem. Możesz zastosować podejście do Tak / Nie lub innego potrzebnego rodzaju.

TOPÓR
źródło
1

Użyj okna dialogowego do prostych okien dialogowych tak lub nie.

Gdy potrzebujesz bardziej skomplikowanych widoków, w których potrzebujesz uzyskać kontrolę nad cyklem życia, takich jak oncreate, żądania uprawnień, dowolne zastąpienie cyklu życia, użyłbym fragmentu okna dialogowego. W ten sposób oddzielasz uprawnienia i każdy inny kod, który okno dialogowe musi obsługiwać bez konieczności komunikowania się z działaniem wywołującym.

Gustavo Baiocchi Costa
źródło