Trying to open an Activity from an AlertDialog in a Fragment

wowbagger :

So, I'm trying to open a new Activity after doing some confirmation on an AlertDialog which is started inside a fragment.

My issue is context. I've already tried using getActivity() and getContext(), both to no avail. The idea is confirming an user action with this dialog (specifically deleting account, so it's important to drive the user to a specific Activity) and, after the confirmation, starting the IntroActivity.

This is the content of my AlertDialog class:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    final AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
    LayoutInflater inflater = getActivity().getLayoutInflater();
    final View view = inflater.inflate(R.layout.layout_excluir_usuario_dialog, null);

    dialog.setView(view)
            .setTitle("Deseja mesmo excluir a sua conta?")
            .setMessage("Excluir a sua conta resultará na eliminação completa dos seus dados do Salarium.")
            .setNegativeButton("Cancelar", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialogInterface, int i) {

                }
            })
            .setPositiveButton("Sim", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
                    FirebaseUser usuario = autenticacao.getCurrentUser();

                    usuario.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if (task.isSuccessful()) {
                                Toast.makeText(dialog.getContext(), "E-mail de redefinição de senha enviado!", Toast.LENGTH_LONG).show();
                                Intent intent = new Intent(getActivity().getApplicationContext(), IntroActivity.class);
                                startActivity(intent);

                            } else {
                                Toast.makeText(dialog.getContext(), "Ocorreu um erro na exclusão da sua conta", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });

                }
            });
    return dialog.create();
}

In the end I keep gettin NullPointerExceptions, no matter what combination of context methods I choose.

    Process: com.filipewilliam.salarium, PID: 19838
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.support.v4.app.FragmentActivity.getApplicationContext()' on a null object reference
        at com.filipewilliam.salarium.fragments.ExcluirUsuarioDialog$1$1.onComplete(ExcluirUsuarioDialog.java:55)
        at com.google.android.gms.tasks.zzj.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)```
ianhanniballake :

AlertDialog automatically dismisses the dialog when the buttons are clicked - i.e., when your setPositiveButton OnClickListener fires. When the dialog is dismissed, the DialogFragment is automatically removed.

Because you're doing asynchronous work, your result returns after the Dialog is dismissed and the DialogFragment is removed. At that point, it is expected that dialog.getContext() would be null and getContext() on the DialogFragment would also be null.

There's no way to change the behavior of AlertDialog to only dismiss after your asynchronous callback completes, but you can hold onto the Context from before you kick off your asynchronous work and use it when your async call completes:

@Override
public void onClick(DialogInterface dialogInterface, int i) {
  final Context context = getContext();
  autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
  FirebaseUser usuario = autenticacao.getCurrentUser();

  suario.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
      if (task.isSuccessful()) {
        Toast.makeText(context, "E-mail de redefinição de senha enviado!", Toast.LENGTH_LONG).show();
        Intent intent = new Intent(context, IntroActivity.class);
        startActivity(intent);

      } else {
        Toast.makeText(context, "Ocorreu um erro na exclusão da sua conta", Toast.LENGTH_SHORT).show();
      }
    }
  });

Note that this has one downside: if your Activity is destroyed while your asynchronous work is running, you are continuing to hold onto a reference to the old Activity rather than letting it immediately be garbage collected. Assuming your task does not take very long, this might not be an issue for you.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=161505&siteId=1