2

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)```
Dor
  • 657
  • 1
  • 5
  • 11
wowbagger
  • 161
  • 6

3 Answers3

1

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.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • I've tried your solution and it didn't work, but I didn't have this notion about the problem being that the dialog gets dismissed imediately. So what I did was new methods to test if the user was signed in/or existent at all in the fragment that calls the Dialog and in the Activity. Now the Dialog works, you can delete your user account and once you do you'll get to the IntroActivity! Thanks a bunch! – wowbagger Sep 07 '19 at 16:11
  • What error did you get when you ran the code? If it was something complaining about not final, I've added `final` to the context in my answer. – ianhanniballake Sep 07 '19 at 16:24
  • Yes @ianhanniballake, I've tried it with `final`. The error was that the Fragment wasn't attached to an Activity. – wowbagger Sep 07 '19 at 17:54
0

I think this may be the issue (Why does AlertDialog.Builder(Context context) only accepts Activity as a parameter?):

getApplicationContext() returns the context for your application, which is mostly the same as your activities context - and the "mostly" is what is throwing you off.

The details are unclear but this is a widely encountered issue, and the typical answer is to use the context that will be writing the alert to the screen.

Note that that is not the one returned by getApplicationContext().

UkFLSUI
  • 5,509
  • 6
  • 32
  • 47
0

The getActivity() method Returns null in your function. You should Pass the Activity Context when you initialize your Dialog. You can do It like the answer here

Once you have the Fight Context (Activity inherits from Context) you can create your intent and Start the Activity from it

Dor
  • 657
  • 1
  • 5
  • 11
Rander Gabriel
  • 637
  • 4
  • 14