Android DialogFragment vs Dialog

244

O Google recomenda que usamos DialogFragmentem vez de um simples Dialogusando Fragments API, mas é absurdo usar um isolado DialogFragmentpor um sim-não caixa de mensagem de confirmação simples. Qual é a melhor prática neste caso?

skayred
fonte
5
Em resumo, entre outras coisas, simples Dialogou AlertDialog.Builder::create()::show()criará uma caixa de diálogo que desaparece quando você gira a tela.
precisa saber é o seguinte

Respostas:

83

Sim, use DialogFragmente onCreateDialogvocê pode simplesmente usar um construtor AlertDialog de qualquer maneira para criar um simples AlertDialogcom os botões de confirmação Sim / Não. Não é muito código.

Com relação à manipulação de eventos em seu fragmento, haveria várias maneiras de fazê-lo, mas eu simplesmente defino uma mensagem Handlerna minha Fragment, transmito-a para o DialogFragmentvia construtor e depois repito as mensagens de volta para o manipulador do meu fragmento, conforme apropriado nos vários eventos de clique. Mais uma vez, várias maneiras de fazer isso, mas o seguinte funciona para mim.

Na caixa de diálogo, mantenha uma mensagem e instancie-a no construtor:

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

Implemente o onClickListenerna sua caixa de diálogo e chame o manipulador conforme apropriado:

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

Editar

E como Messageé parcelável, você pode salvá-lo onSaveInstanceStatee restaurá-lo

outState.putParcelable("okMessage", okMessage);

Então em onCreate

if (savedInstanceState != null) {
    okMessage = savedInstanceState.getParcelable("okMessage");
}
PJL
fonte
4
O problema não é okMessage - o problema é okMessage, targetque será nulo se você o carregar de um Bundle. Se o destino de uma mensagem for nulo e você usar sendToTarget, você receberá uma NullPointerException - não porque a mensagem seja nula, mas porque seu destino é.
hrnt
2
Quais são as vantagens de usar DialogFragment em vez de um Dialog?
Raphael Petegrosso
79
A vantagem de usar um DialogFragment é que todo o ciclo de vida do diálogo será tratado por você. Você nunca receberá o erro 'a caixa de diálogo vazou ...' novamente. Vá para DialogFragment e esqueça Dialogs.
Snicolas 13/03/2019
6
Eu acho que setArguments () e getArguments () devem ser usados ​​em vez de passar o okMessage através do construtor.
pjv
1
Bem, eu utilizador Builder muito facilmente e eu gerenciamento de atividades punho com este android: configChanges = "locale | keyboardHidden | orientação | screensize" e eu não vejo nenhum problema em aplicações ...
Renetik
67

Você pode criar subclasses DialogFragment genéricas como YesNoDialog e OkDialog e transmitir título e mensagem se usar muito diálogos em seu aplicativo.

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

Em seguida, chame-o usando o seguinte:

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

E lide com o resultado onActivityResult.

ashishduh
fonte
Sim, o DialogFragment lida com todos os eventos do ciclo de vida para você.
ashishduh
1
Eu acho que não, porque após a rotação o diálogo antigo ainda existe e se mantém atribuído ao fragmento antigo não existente (dialog.setTargetFragment (this, YES_NO_CALL);); portanto, após a rotação, getTargetFragment (). OnActivityResult não funciona
Malachiasz
7
quais são YES_NO_CALL, getFragmentManager()e onActivityResult?
msysmilu
2
YES_NO_CALLé um int personalizado que é o código de solicitação. getFragmentManager()obtém o gerenciador de fragmentos da atividade e onActivityResult()é um método de retorno de chamada do ciclo de vida do fragmento.
ashishduh
3
Substitua getFragmentManager () por getSupportFragmentManager ();
precisa
33

Use DialogFragment sobre AlertDialog:


  • Desde a introdução do nível 13 da API :

    o método showDialog de Activity foi descontinuado . Não é aconselhável chamar uma caixa de diálogo em outro lugar no código, pois você deverá gerenciar a caixa de diálogo por conta própria (por exemplo, mudança de orientação).

  • Diferença DialogFragment - AlertDialog

    Eles são muito diferentes? Da referência do Android sobre o DialogFragment :

    Um DialogFragment é um fragmento que exibe uma janela de diálogo flutuando sobre a janela de sua atividade. Este fragmento contém um objeto de Diálogo, que é exibido conforme apropriado com base no estado do fragmento. O controle da caixa de diálogo (decidir quando mostrar, ocultar, dispensar) deve ser feito através da API aqui , não com chamadas diretas na caixa de diálogo.

  • Outras notas

    • Fragmentos são uma evolução natural na estrutura do Android devido à diversidade de dispositivos com diferentes tamanhos de tela.
    • DialogFragments e Fragments são disponibilizados na biblioteca de suporte, o que torna a classe utilizável em todas as versões atuais usadas do Android.
Tobrun
fonte
28

Eu recomendaria usar DialogFragment.

Certamente, a criação de uma caixa de diálogo "Sim / Não" com ela é bastante complexa, considerando que deve ser uma tarefa bastante simples, mas a criação de uma caixa de diálogo semelhante também Dialogé surpreendentemente complicada.

(O ciclo de vida da atividade torna tudo complicado - você deve Activitygerenciar o ciclo de vida da caixa de diálogo - e não há como passar parâmetros personalizados, como a mensagem personalizada, se Activity.showDialogestiver usando níveis de API abaixo de 8)

O bom é que você geralmente pode criar sua própria abstração DialogFragmentfacilmente.

hrnt
fonte
Como você lida com retornos de chamada de diálogo de alerta (sim, não)?
Alexey Zakharov
A maneira mais fácil seria implementar um método na Atividade de hospedagem que aceita um Stringparâmetro. Quando o usuário clica em "Sim", por exemplo, a caixa de diálogo chama o método da Atividade com o parâmetro "concordo". Esses parâmetros são especificados ao exibir a caixa de diálogo, por exemplo, AskDialog.ask ("Você concorda com estes termos?", "Concorda", "discorda");
hrnt
5
Mas eu preciso de retorno de chamada dentro do fragmento, não atividade. Eu posso usar setTargetFragment e convertê-lo na interface. Mas é o inferno.
Alexey Zakharov
Você também pode buscar o fragmento de destino definindo uma tag para o destino e usando FragmentManager's findFragmentByTag. Mas sim, isso requer um pouco de código.
hrnt
@AlexeyZakharov Eu sei que isso é cerca de 5 anos atrasado, mas você pode passar Fragment this e ter o Activity extendsseu Interface. Cuidado com o encadeamento, porém, você pode ativar as chamadas de interface quando não necessariamente as deseja, se sua simultaneidade não estiver sob controle. Não tenho certeza do que isso faz com a memória e os espaguetes de dependência circular, alguém mais gostaria de conversar? A outra opção é Message/ Handlermas você ainda pode ter problemas de simultaneidade.
Tricknology 24/03
8

AlertDialogFragment genérico com padrão Builder

No meu projeto, eu já utilizado AlertDialog.Buildermuito antes de eu descobri que ele é problemático. No entanto, eu não queria alterar muito código em nenhum lugar do meu aplicativo. Além disso, sou fã de passar OnClickListenerscomo classes anônimas onde elas são necessárias (ou seja, ao usar setPositiveButton(),setNegativeButton() etc.) em vez de ter de implementar milhares de métodos de retorno de chamada para a comunicação entre um fragmento de diálogo e o fragmento de suporte, que pode, em na minha opinião, levar a um código muito confuso e complexo. Especialmente, se você tiver várias caixas de diálogo diferentes em um fragmento e precisar distinguir nas implementações de retorno de chamada entre a caixa de diálogo exibida no momento.

Portanto, combinei diferentes abordagens para criar uma AlertDialogFragmentclasse auxiliar genérica que pode ser usada exatamente como AlertDialog :


SOLUÇÃO

( Observe que estou usando expressões lambda do Java 8 no meu código, portanto, talvez você precise alterar partes do código se ainda não estiver usando expressões 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
}

USO

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

Estou postando isso aqui não apenas para compartilhar minha solução, mas também porque gostaria de pedir a opinião de vocês: Esta abordagem é legítima ou problemática até certo ponto?

flxapps
fonte
3
Essa é uma ideia muito interessante, mas não acho que o design da API funcione. Se você passar um OnClickListener para setPositiveButton (), quando o dispositivo for girado e o fragmento for recriado dos argumentos do pacote, os OnClickListeners não serão recriados adequadamente do Parcelable. A questão fundamental é que você não pode recriar um ouvinte durante a rotação, mas a interface da API (que aceita interfaces) exige isso. Eu gostaria que este não fosse o caso (como eu gosto da idéia).
Xargs 24/05
1
Boa ideia, mas como o @Xargs diz, não funciona. Os ouvintes passados ​​não são recriados corretamente na rotação.
Graham Borland
Meus resultados são que ele realmente funciona na rotação e no reinício do aplicativo (depois de ir para a tela inicial, por exemplo), mas não quando a atividade é restaurada após ter sido completamente destruída (os OnClickListeners estão realmente perdidos). (Testado no Android 4.4.4 e Android 5.1.1)
flxapps
Não testei essa implementação exata, mas pelo que testei, um ouvinte parcelável passado para um pacote de fragmentos é chamado corretamente na recriação. Não tenho idéia do porquê, mas parece funcionar.
precisa
@flxapps, no caso da visualização personalizada, como você pode obter as visualizações filho e alterar suas propriedades ou aplicar ouvintes? Em sua classe que não estão retornando qualquer instância de diálogo e que poderia causar uma exceção se alguém vai tentar obter vistas criança
Zubair Rehman
5

Posso sugerir uma pequena simplificação da resposta de @ 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();
}

Isso elimina a necessidade de o usuário (da classe) estar familiarizado com os componentes internos do componente e torna o uso realmente simples:

AlertDialogFragment.showAlert(title, message, this);

PS No meu caso, eu precisava de uma caixa de diálogo de alerta simples, e foi isso que criei. Você pode aplicar a abordagem a um Sim / Não ou a qualquer outro tipo necessário.

MACHADO
fonte
1

Use o Diálogo para diálogos simples de sim ou não.

Quando você precisa de visualizações mais complexas nas quais precisa se apossar do ciclo de vida, como oncreate, solicitar permissões, qualquer substituição do ciclo de vida eu usaria um fragmento de diálogo. Assim, você separa as permissões e qualquer outro código que a caixa de diálogo precise operar sem precisar se comunicar com a atividade de chamada.

Gustavo Baiocchi Costa
fonte