Android DialogFragment vs Dialog

244

Google empfiehlt, dass wir DialogFragmentanstelle einer einfachen DialogVerwendung verwenden Fragments API, aber es ist absurd, eine isolierte DialogFragmentfür eine einfache Ja-Nein-Bestätigungsmeldung zu verwenden. Was ist in diesem Fall die beste Vorgehensweise?

skayred
quelle
5
Kurz gesagt, unter anderem einfach Dialogoder AlertDialog.Builder::create()::show()erstellt ein Dialogfeld, das beim Drehen des Bildschirms verschwindet.
user1032613

Antworten:

83

Ja, verwenden Sie DialogFragmentund in können onCreateDialogSie trotzdem einfach einen AlertDialog-Builder verwenden, um eine einfache AlertDialogBestätigungsschaltfläche mit Ja / Nein zu erstellen . Überhaupt nicht sehr viel Code.

In Bezug auf die Behandlung von Ereignissen in Ihrem Fragment gibt es verschiedene Möglichkeiten, dies zu tun. Ich definiere jedoch einfach eine Nachricht Handlerin meinem Fragment, übergebe sie DialogFragmentüber den Konstruktor an und übergebe dann Nachrichten an den Handler meines Fragments zurück , um sie für die verschiedenen Klickereignisse zu verwenden. Wieder verschiedene Möglichkeiten, aber das Folgende funktioniert für mich.

Halten Sie im Dialogfeld eine Nachricht und instanziieren Sie sie im Konstruktor:

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

Implementieren Sie das onClickListenerin Ihrem Dialog und rufen Sie den Handler entsprechend auf:

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

Bearbeiten

Und wie Messagees paketierbar ist, können Sie es speichern onSaveInstanceStateund wiederherstellen

outState.putParcelable("okMessage", okMessage);

Dann in onCreate

if (savedInstanceState != null) {
    okMessage = savedInstanceState.getParcelable("okMessage");
}
PJL
quelle
4
Das Problem ist nicht okMessage - das Problem ist okMessage, targetdas null ist, wenn Sie es aus einem Bundle laden. Wenn das Ziel einer Nachricht null ist und Sie verwenden sendToTarget, erhalten Sie eine NullPointerException - nicht weil die Nachricht null ist, sondern weil ihr Ziel ist.
2.
2
Welche Vorteile bietet die Verwendung von DialogFragment anstelle eines Dialogs?
Raphael Petegrosso
79
Der Vorteil der Verwendung eines DialogFragments besteht darin, dass der gesamte Lebenszyklus des Dialogs für Sie abgewickelt wird. Sie werden nie wieder die Fehlermeldung "Dialog ist durchgesickert ..." erhalten. Gehen Sie zu DialogFragment und vergessen Sie Dialoge.
Snicolas
6
Ich denke, setArguments () und getArguments () sollten verwendet werden, anstatt die okMessage über den Konstruktor zu übergeben.
pjv
1
Nun, ich User Builder ziemlich einfach und ich handhabe Aktivitätsmanagement mit diesem Android: configChanges = "locale | keyboardHidden | Orientierung | screenSize" und ich sehe keine Probleme in Anwendungen ...
Renetik
67

Sie können generische DialogFragment-Unterklassen wie YesNoDialog und OkDialog erstellen und Titel und Nachricht übergeben, wenn Sie in Ihrer App häufig Dialoge verwenden.

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();
    }
}

Rufen Sie es dann wie folgt auf:

    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");

Und behandeln Sie das Ergebnis in onActivityResult.

Ashishduh
quelle
Ja, DialogFragment behandelt alle Lebenszyklusereignisse für Sie.
Ashishduh
1
Ich denke, dies ist nicht der Fall, da nach der Rotation der alte Dialog noch vorhanden ist und dem alten, nicht vorhandenen Fragment (dialog.setTargetFragment (this, YES_NO_CALL);) zugewiesen bleibt. Nach der Rotation funktioniert getTargetFragment (). OnActivityResult funktioniert nicht
Malachiasz
7
was ist YES_NO_CALL, getFragmentManager()und onActivityResult?
Msysmilu
2
YES_NO_CALList ein benutzerdefiniertes int, das der Anforderungscode ist. getFragmentManager()Ruft den Fragmentmanager für die Aktivität ab und onActivityResult()ist eine Rückrufmethode für den Fragmentlebenszyklus.
Ashishduh
3
Ersetzen Sie getFragmentManager () durch getSupportFragmentManager ();
Avinash Verma
33

Verwenden Sie DialogFragment über AlertDialog:


  • Seit der Einführung von API Level 13 :

    Die showDialog- Methode von Activity ist veraltet . Das Aufrufen eines Dialogfelds an einer anderen Stelle im Code ist nicht ratsam, da Sie das Dialogfeld selbst verwalten müssen (z. B. Änderung der Ausrichtung).

  • Differenz DialogFragment - AlertDialog

    Sind sie so unterschiedlich? Aus der Android-Referenz zu DialogFragment :

    Ein DialogFragment ist ein Fragment, das ein Dialogfenster anzeigt, das über dem Fenster seiner Aktivität schwebt. Dieses Fragment enthält ein Dialogobjekt, das je nach Status des Fragments entsprechend angezeigt wird. Die Steuerung des Dialogs ( die Entscheidung , wann anzuzeigen, auszublenden, die Klage) sollten über die API erfolgen hier , nicht mit direktem fordert den Dialog.

  • Weitere Hinweise

    • Fragmente sind aufgrund der Vielfalt der Geräte mit unterschiedlichen Bildschirmgrößen eine natürliche Weiterentwicklung des Android-Frameworks.
    • DialogFragments und Fragmente werden in der Support-Bibliothek zur Verfügung gestellt, wodurch die Klasse in allen derzeit verwendeten Android-Versionen verwendet werden kann.
Tobrun
quelle
28

Ich würde empfehlen, zu verwenden DialogFragment .

Sicher, das Erstellen eines "Ja / Nein" -Dialogs damit ist ziemlich komplex, wenn man bedenkt, dass es eine ziemlich einfache Aufgabe sein sollte, aber ein ähnliches Dialogfeld mit Dialog ist auch überraschend kompliziert.

(Der Aktivitätslebenszyklus macht es kompliziert - Sie müssen Activityden Lebenszyklus des Dialogfelds verwalten lassen - und es gibt keine Möglichkeit, benutzerdefinierte Parameter, z. B. die benutzerdefinierte Nachricht, an zu übergebenActivity.showDialog API-Ebenen unter 8 zu übergeben.)

Das Schöne ist, dass Sie normalerweise DialogFragmentganz einfach Ihre eigene Abstraktion darauf aufbauen können.

hrnt
quelle
Wie werden Sie mit Rückrufen im Alarmdialog umgehen (ja, nein)?
Alexey Zakharov
Der einfachste Weg wäre, eine Methode in der Hosting-Aktivität zu implementieren, die einen StringParameter akzeptiert. Wenn der Benutzer beispielsweise auf "Ja" klickt, ruft der Dialog die Methode der Aktivität mit dem Parameter "Zustimmen" auf. Diese Parameter werden beim Anzeigen des Dialogfelds angegeben, z. B. AskDialog.ask ("Stimmen Sie diesen Begriffen zu?", "Zustimmen", "Nicht zustimmen").
2.
5
Aber ich brauche einen Rückruf innerhalb des Fragments, keine Aktivität. Ich kann setTargetFragment verwenden und es in die Schnittstelle umwandeln. Aber es ist die Hölle.
Alexey Zakharov
Sie können das Zielfragment auch abrufen, indem Sie ein Tag für das Ziel festlegen und FragmentManager's verwenden findFragmentByTag. Aber ja, es erfordert ein gutes Stück Code.
2.
@AlexeyZakharov Ich weiß, dass dies ungefähr 5 Jahre zu spät ist, aber Sie könnten das bestehen Fragment this und Ihr Activity extendsIhr haben Interface. Wenn Sie jedoch auf Threading achten, können Sie Schnittstellenaufrufe abbrechen, wenn Sie diese nicht unbedingt möchten, wenn Ihre Parallelität nicht überprüft wird. Sie sind sich nicht sicher, was dies mit Spaghetti mit Gedächtnis und zirkulärer Abhängigkeit zu tun hat. Die andere Option ist Message/, Handleraber Sie haben möglicherweise immer noch Probleme mit der Parallelität.
Tricknologie
8

Generisches AlertDialogFragment mit Builder-Muster

In meinem Projekt habe ich bereits AlertDialog.Builderschon viel , bevor ich herausfand, dass es problematisch ist. Ich wollte jedoch nirgendwo in meiner App so viel Code ändern. Außerdem bin ich ein Fan davon, OnClickListenersals anonyme Klassen dort zu bestehen, wo sie benötigt werden (dh wenn ich sie benutze) setPositiveButton().setNegativeButton() etc.) anstelle von Tausenden von Callback - Methoden zu implementieren zwischen einem Dialogfragment und dem Halter Fragment zu kommunizieren, was kann, in Meiner Meinung nach führt dies zu sehr verwirrendem und komplexem Code. Insbesondere, wenn Sie mehrere verschiedene Dialoge in einem Fragment haben und dann in den Rückrufimplementierungen unterscheiden müssen, welche Dialoge gerade angezeigt werden.

Daher habe ich verschiedene Ansätze kombiniert, um eine generische AlertDialogFragmentHilfsklasse zu erstellen , die genau wie folgt verwendet werden kann AlertDialog:


LÖSUNG

( BITTE BEACHTEN SIE, dass ich in meinem Code Java 8-Lambda-Ausdrücke verwende. Wenn Sie noch keine Lambda-Ausdrücke verwenden, müssen Sie möglicherweise Teile des Codes ändern .)

/**
 * 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
}

VERWENDUNG

// 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();

Ich poste dies hier nicht nur, um meine Lösung zu teilen, sondern auch, weil ich Sie nach Ihrer Meinung fragen wollte: Ist dieser Ansatz in gewissem Maße legitim oder problematisch?

flxapps
quelle
3
Dies ist eine sehr interessante Idee, aber ich denke nicht, dass das API-Design funktioniert. Wenn Sie einen OnClickListener an setPositiveButton () übergeben, wenn das Gerät gedreht und das Fragment aus den Bundle-Argumenten neu erstellt wird, werden die OnClickListener aus dem Parcelable nicht ordnungsgemäß neu erstellt. Das grundlegende Problem ist, dass Sie einen Listener während der Rotation nicht neu erstellen können, die API-Schnittstelle (die Schnittstellen verwendet) dies jedoch erfordert. Ich wünschte, das wäre nicht der Fall (da mir die Idee gefällt).
Xargs
1
Gute Idee, aber wie @Xargs sagt, funktioniert es nicht. Die übergebenen Listener werden beim Drehen nicht korrekt neu erstellt.
Graham Borland
Mein Ergebnis ist, dass es tatsächlich bei der Rotation und bei der Wiederaufnahme der App funktioniert (z. B. nach dem Aufrufen des Startbildschirms), jedoch nicht, wenn die Aktivität wiederhergestellt wird, nachdem sie vollständig zerstört wurde (dann gehen die OnClickListener tatsächlich verloren). (Getestet auf Android 4.4.4 und Android 5.1.1)
flxapps
Ich habe diese genaue Implementierung nicht getestet, aber nach dem, was ich getestet habe, wird ein Paket-Listener, der an ein Fragment-Bundle übergeben wurde, beim erneuten Erstellen korrekt aufgerufen. Ich habe keine Ahnung warum, aber es scheint zu funktionieren.
Saad Farooq
@flxapps, wie können Sie im Fall einer benutzerdefinierten Ansicht die untergeordneten Ansichten abrufen und ihre Eigenschaften ändern oder Listener anwenden? In Ihrer Klasse geben Sie keine Dialoginstanz zurück und das könnte eine Ausnahme verursachen, wenn jemand versucht, untergeordnete Ansichten zu erhalten
Zubair Rehman
5

Darf ich eine kleine Vereinfachung der Antwort von @ ashishduh vorschlagen:

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();
}

Der Benutzer (der Klasse) muss nicht mehr mit den Interna der Komponente vertraut sein, und die Verwendung ist sehr einfach:

AlertDialogFragment.showAlert(title, message, this);

PS In meinem Fall brauchte ich einen einfachen Warndialog, also habe ich das erstellt. Sie können den Ansatz auf ein Ja / Nein oder einen anderen Typ anwenden, den Sie benötigen.

AXT
quelle
1

Verwenden Sie Dialog für einfache Ja- oder Nein-Dialoge.

Wenn Sie komplexere Ansichten benötigen, in denen Sie den Lebenszyklus erfassen müssen, z. B. Oncreate, Anforderungsberechtigungen oder Überschreibungen des Lebenszyklus, würde ich ein Dialogfragment verwenden. Auf diese Weise trennen Sie die Berechtigungen und jeden anderen Code, den der Dialog ausführen muss, ohne mit der aufrufenden Aktivität kommunizieren zu müssen.

Gustavo Baiocchi Costa
quelle