Why Does Alertdialog.Builder(Context Context) Only Accepts Activity as a Parameter

Why does AlertDialog.Builder(Context context) only accepts Activity as a parameter?

An Activity inherits a Context. AlertDialog.Builder specifies a Context argument because it can then be used by ANY class that is a subclass of Context, including an Activity, ListActivity, Service, ... (There is a common coding idiom behind this - you can learn more about it by reading Item I8 (on Interfaces and Abstract classes) in Joshua Bloch's fantastic Effective Java).

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().

Now if you're like me, you may say "but I am working in a class that does not inherit from Activity - which is why I want to use getApplicationContext() for this in the first place - duh!" I'm actually don't speak as rudely as that ;p .. the point was I've been here too. I fixed it like so: 1) ask yourself "do I have my UI AlertDialog code in a non-activity class because I want to share it across activities .. or even across ListActivities, Services, ...?". If not, hmmm... do you really have AlertDialog UI calls in code that you can't guarantee will have access to the UI (and thus context)? If so, reconsider your design.

Presuming you do want to share this class across Activities, ... the answer becomes clear. You want your class to be usable by a variety of callers, each probably with its own context: so the caller must pass its context into your class as an argument:

myClass(Context theContext, ...) { ... }

Each activity, service, etc. then makes calls like so:

myClass(this, ...);

Look familiar?

Do be careful! that if you are sharing code, you must consider the possibility of different calls coming into your shared code in parallel, with all the many ramifications. Thats beyond our scope here...

Have fun :)

AlertDialog - Activity vs Application Context

There are two types of Context:

Application context is associated with the application and will always be same throughout the life of application -- it does not change. So if you are using Toast, you can use application context or even activity context (both) because toast can be displayed from anywhere with in your application and is not attached to a specific window. But there are many exceptions, one exception is when you need to use or pass the activity context.

Activity context is associated with to the activity and can be destroyed if the activity is destroyed -- there may be multiple activities (more than likely) with a single application. And sometimes you absolutely need the activity context handle. For example, should you launch a new activity, you need to use activity context in its Intent so that the new launching activity is connected to the current activity in terms of activity stack. However, you may use application's context too to launch a new activity but then you need to set flag Intent.FLAG_ACTIVITY_NEW_TASK in intent to treat it as a new task.

For more details

why adding the class name in AlertDialog.Builder parameter?

The class Activity is a sub-class of Context so you can use it as parameter in your example.
Now if for instance, you are inside an onClick method (i.e. button) or inside an inner class or an asynctask, using 'this' would not refer the activity itself so you need to use YourActivity.this.

Instead when you see ClassName.class it usually is because you need to specify wich activity, service or whatever you want to start, in that case the parameter type is Class.
For example if you want to start an activity, you use:

Intent intent = new Intent(this or ActivityName.this, AnotherActivityName.class);

For example:

public class MyActivity extends Activity {
....

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// in this case 'this' refers the current activity instance
// (but of course you can also use MyActivity.this
myAdapter = new ArrayAdapter(this, R.layout.list_item, items);

...

myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// here you must use ActivityName.this because
// 'this' refers to the OnClickListner instance
Intent intent = new Intent(ActivityName.this, AnotherActivityNameActivityName.class);
startActivity(intent);
}
});

...
}

Alert Dialog.Builder(??)

Although AlertDialog.Builder() accepts a Context reference in its argument, it is better to pass an Activity reference to it, not applicationContext because of potential theme and window attachment problems. So, pass an Activity reference to your adapter and use it to build an AlertDialog.

public class ProductAdapter extends SomeAdapter {

private Activity create;

public ProductAdapter(Activity activity, List<Product> productList) {
create = activity;
this.productList = productList;
}

private void showAlertDialog(){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(create);
// ...
alertDialogBuilder.create().show();
}

}

Trying to open an Activity from an AlertDialog in a Fragment

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.

Show dialog only using Context instead of Activity instance

The problem is something I faced recently too, you cant create a dialog without and activity instance. getApplicationContext() call doesn't work too. The way I did this is to make the call to a method that creates the dialog, from an activity, and pass "this" i.e. the reference to that activity as a parameter.

If you are going to reuse this code, as a reusable component or as a mechanism to create dialogs at multiple places, create a base activity class and have this method in there, and use it in sub-classed activities as needed.



Related Topics



Leave a reply



Submit