Dialog throwing "Unable to add window — token null is not for an application” with getApplication() as context
Asked Answered
S

28

695

My Activity is trying to create an AlertDialog which requires a Context as a parameter. This works as expected if I use:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

However, I am leery of using "this" as a context due to the potential for memory leaks when Activity is destroyed and recreated even during something simple like a screen rotation. From a related post on the Android developer's blog:

There are two easy ways to avoid context-related memory leaks. The most obvious one is to avoid escaping the context outside of its own scope. The example above showed the case of a static reference but inner classes and their implicit reference to the outer class can be equally dangerous. The second solution is to use the Application context. This context will live as long as your application is alive and does not depend on the activities life cycle. If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() or Activity.getApplication().

But for the AlertDialog() neither getApplicationContext() or getApplication() is acceptable as a Context, as it throws the exception:

"Unable to add window — token null is not for an application”

per references: 1, 2, 3, etc.

So, should this really be considered a "bug", since we are officially advised to use Activity.getApplication() and yet it doesn't function as advertised?

Jim

Stook answered 26/4, 2011 at 21:21 Comment(7)
reference for the first item where R.Guy advises using getApplication: android-developers.blogspot.com/2009/01/…Stook
other references: #1562303Stook
other reference:#2635491Stook
groups.google.com/group/android-developers/browse_thread/thread/…Stook
Related: Android 1.6: "android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application"Falbala
It's an interesting question. I wish someone would answer your question; So, should this really be considered a "bug", since we are officially advised to use Activity.getApplication() and yet it doesn't function as advertised?Interregnum
Possible duplicate of Android 'Unable to add window -- token null is not for an application' exceptionValli
M
1405

Instead of getApplicationContext(), just use ActivityName.this.

Musicale answered 29/8, 2011 at 11:4 Comment(22)
Great! Just to comment on that.. you may sometimes need to store "this" globally, (for example) in order to access it within a listener's implemented method who has it's own 'this'. In that case, you'd define "Context context" globally, and then in the onCreate, set "context = this", and then refer to "context". Hope that comes in handy too.Musicale
Actually, as Listener classes are often anonymous-inner, I tend to just do final Context ctx = this; and I'm away ;)Amritsar
@StevenL In order to do what you're saying, you should use ExternalClassName.this to explicitly refer to "this" of the outer class.Isolda
Wouldn't using "this" leak it if your dialog is used in a callback and you leave the activity before the callback is called? At least that's what Android seems to complain about in logcat.Isolda
@StevenL could you add some reasoning behind this?Garniture
Thanks for the suggestions. I know using "this" works, but I also have experienced significant memory leaks using "this", which disappear if I avoid using it...Stook
How this is work inside receiver, In Broadcast Receiver , onReceiver method have context object of Context, In Broadcast Receiver, we can't use "this" .Brainsick
for me i use the "this" by passing it to another class constructor, and that works perfectly !Praedial
You can use yourActivity.this if you are used in functionBoylston
I would not advise @StevenLs approach as you can easily leak the memory of that activity unless you remember to clear the static reference in onDestroy - Artem is correct. StevenLs approach is bourne from a lack of understanding how Java worksArtair
so why does getApplicationContext() gives error @Dori?Dorsad
by my comment above I'm referring to @StevenL comment above containing "sometimes need to store this globally". Storing an Activity context (which is what this is referring to in this case) in a static field is a big no-no as its really easy to leak memory. @Artems approach of "ExternalClassName.this" is most definitely the correct one. getApplicationContext() probably gives the error due to a dialog needing to be attached to the Activity context as opposed to the Application context...Artair
...Android has a bit of ambiguity when it comes to the Context class, especially as Activity and Application both extend context but have differnt external state and in not all situations and truely substitutable for each other, which sort of goes against the L part of SOLID OOP design priciples - and hence leads to confusion such as the OPs issue.Artair
Your solution worked for me when I am using ActivityName.this, so I edited your answer so that it will help other also... Generally Devs are assigning Dialog as static so for this they need to use their ActivityName.this instead of getAppLicationContext()Eliza
So basically we get the choice to violate Android's design principles and purposefully leak the activity it's attached to OR miss out on a lot of functionality.Suannesuarez
I was at this for ages and didn't know what it was that was the issue! Thanks :)Malarkey
I had an issue with putting my custom api in asynctask, and using myactivity.this as a context worked like a charm. ThanksHesperidin
This is not an answer to the question. The question is: Why does AlertDialog.Build(Context context) only work when you pass an Activity as the context? Or, asked the other way: Why doesn't AlertDialog.Build(Context context) work when you pass a context that is not an Activity?Sfumato
Or if you're getting this error from within a Fragment, use getActivity().Diacritic
You rocks the day ,super) ActivityName.this.Haaf
i test it bot not working . i fix it with createing currentActivity variable in application class and i set it in all activites.Mittiemittimus
What is ActivityName in PreferenceFragment?Hanks
P
201

Using this did not work for me, but MyActivityName.this did.

Pestana answered 21/6, 2012 at 0:54 Comment(1)
That's what happens when you use this from inside of an inner class. If you want to reference the instance of an outer class, you must specify so, as you do with OuterClass.this. Just using this always references the most inner class' instance.Ait
R
64

You can continue to use getApplicationContext(), but before use, you should add this flag: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT), and the error will not show.

Add the following permission to your manifest:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Replica answered 25/12, 2014 at 8:9 Comment(6)
I get Unable to add window android.view.ViewRootImpl$W@426ce670 -- permission denied for this window typeLawrencelawrencium
add permission: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>Replica
Seems like you cannot enable this permission in API 23 onwards code.google.com/p/android-developer-preview/issues/…Unabridged
You can use it for API 23 onwards, however you need to prompt the user: startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), OVERLAY_PERMISSION_REQ_CODE); however, whether you should use it is another matter...Ilia
This is useful when you are showing progress dialog inside serviceAcidosis
This also works with Presentation, my secondary display doesn't flicker anymore since I've provided my application context as context.Mcfadden
T
42

You've correctly identified the problem when you said "... for the AlertDialog() neither getApplicationContext() or getApplication() is acceptable as a Context, as it throws the exception: 'Unable to add window — token null is not for an application'"

To create a Dialog, you need an Activity Context or a Service Context, not an Application Context (both getApplicationContext() and getApplication() return an Application Context).

Here's how you get the Activity Context:

(1) In an Activity or a Service:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

(2) In a Fragment: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

Memory leaks is not a problem that is intrinsic to the "this" reference, which is an object's reference to itself (i.e. reference to the actual allocated memory for storing the object's data). It happens to any allocated memory for which the Garbage Collector (GC) is unable to free up after the allocated memory has outlived its useful lifespan.

Most of the time, when a variable goes out of scope, the memory will be reclaimed by the GC. However, memory leaks can occur when the reference to an object held by a variable, say "x", persists even after the object has outlived its useful lifespan. The allocated memory will hence be lost for as long as "x" holds a reference to it because GC will not free up the memory for as long as that memory is still being referenced. Sometimes, memory leaks are not apparent because of a chain of references to the allocated memory. In such a case, the GC will not free up the memory until all references to that memory have been removed.

To prevent memory leaks, check your code for logical errors that cause allocated memory to be referenced indefinitely by "this" (or other references). Remember to check for chain references as well. Here are some tools you can use to help you analyze memory use and find those pesky memory leaks:

Tsunami answered 7/10, 2016 at 23:37 Comment(1)
For an Activity you can also use ActivityName.this where ActivityName is (obviously) your activity's name (for example MainActivity)Herbart
S
34

Your dialog should not be a "long-lived object that needs a context". The documentation is confusing. Basically if you do something like:

static Dialog sDialog;

(note the static)

Then in an activity somewhere you did

 sDialog = new Dialog(this);

You would likely be leaking the original activity during a rotation or similar that would destroy the activity. (Unless you clean up in onDestroy, but in that case you probably wouldn't make the Dialog object static)

For some data structures it would make sense to make them static and based off the application's context, but generally not for UI related things, like dialogs. So something like this:

Dialog mDialog;

...

mDialog = new Dialog(this);

Is fine and shouldn't leak the activity as mDialog would be freed with the activity since it's not static.

Scurrilous answered 26/6, 2011 at 7:56 Comment(2)
i'm calling it from an asynctask, this worked for me, thx mateTrevatrevah
my dialog was static, once i removed the static declaration it worked.Transverse
S
28

in Activity just use:

MyActivity.this

in Fragment:

getActivity();
Scyphus answered 24/4, 2018 at 10:41 Comment(1)
This fixed it for me in my Activity. ThanksExiguous
G
26

I had to send my context through a constructor on a custom adapter displayed in a fragment and had this issue with getApplicationContext(). I solved it with:

this.getActivity().getWindow().getContext() in the fragments' onCreate callback.

Ginoginsberg answered 10/9, 2014 at 1:41 Comment(3)
This worked for me too, I passed it to the constructor of external AsyncTask that I am using (It shows a progress Dialog).Antebellum
this is the REAL answer for more complex tasks :)Underclothes
I agree with the @UnderclothesTuttle
O
22

***** kotlin version *****

You should pass this@YourActivity instead of applicationContext or baseContext

Octavie answered 20/10, 2018 at 11:47 Comment(0)
N
20

In Activity on click of button showing a dialog box

Dialog dialog = new Dialog(MyActivity.this);

Worked for me.

Nutcracker answered 27/2, 2013 at 11:26 Comment(0)
T
19

Just use following:

FOR JAVA USERS

In case you are using activity --> AlertDialog.Builder builder = new AlertDialog.Builder(this);

OR

AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);

In case you are using fragment --> AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());

FOR KOTLIN USERS

In case you are using activity --> val builder = AlertDialog.Builder(this)

OR

val builder = AlertDialog.Builder(this@your_activity)

In case you are using fragment --> val builder = AlertDialog.Builder(requireActivity())

Tracietracing answered 30/11, 2019 at 7:50 Comment(0)
A
18

Little hack: you can prevent destroying your activity by GC (you should not do it, but it can help in some situations. Don't forget to set contextForDialog to null when it's no longer needed):

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}
Acetanilide answered 3/12, 2012 at 10:3 Comment(1)
@MurtuzaKabul It works because this == PostActivity which inherits from Activity-> which inherits from Context, so when you pass the dialog your context you are actually passing the activityCrowbar
G
13

If you are using a fragment and using AlertDialog/Toast message then use getActivity() in the context parameter.

like this

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();
Guilder answered 23/11, 2013 at 15:43 Comment(0)
R
9

adding

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

and

"android.permission.SYSTEM_ALERT_WINDOW"/> in manifest

It works for me now. After even close and open the application, gave me the error at that time.

Redound answered 21/4, 2015 at 11:6 Comment(0)
C
9

I was using ProgressDialog in a fragment and was getting this error on passing getActivity().getApplicationContext() as the constructor parameter. Changing it to getActivity().getBaseContext() didn't work either.

The solution that worked for me was to pass getActivity(); i.e.

progressDialog = new ProgressDialog(getActivity());

Chretien answered 4/11, 2016 at 14:18 Comment(0)
P
6

Use MyDialog md = new MyDialog(MyActivity.this.getParent());

Preeminence answered 1/5, 2013 at 7:42 Comment(0)
P
6

If you are outside of the Activity then you need to use in your function "NameOfMyActivity.this" as Activity activity, example:

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);
Poplar answered 1/7, 2014 at 22:29 Comment(0)
H
5

If you are using a fragment and using an AlertDialog / Toast message, use getActivity() in the context parameter.

Worked for me.

Cheers!

Hymnology answered 12/1, 2013 at 4:5 Comment(0)
P
5

Try to use the context of an activity which will be under the dialog. But be carefull when you use "this" keyword, because it will not work everytime.

Forexample, if you have TabActivity as host with two tabs, and each tab is another activity, and if you try to create dialog from one of the tabs (activities) and if you use "this", then you will get exception, In this case dialog should be connected to host activity which host everything and visible. (you can say most visible parent Activity's context)

I did not find this info from any document but by trying. This is my solution without strong background, If anybody with better knownledge, feel free to comment.

Pigweed answered 22/8, 2013 at 8:33 Comment(0)
S
5

For future readers, this should help:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}
Stopgap answered 20/9, 2016 at 14:36 Comment(0)
M
3

Try getParent() at the argument place of context like new AlertDialog.Builder(getParent()); Hope it will work, it worked for me.

Marcus answered 5/2, 2013 at 7:27 Comment(0)
C
2

In my case work:

this.getContext();
Correct answered 29/11, 2012 at 12:7 Comment(0)
N
2

I think it may happen as well if you are trying to show a dialog from a thread which is not the main UI thread.

Use runOnUiThread() in that case.

Nostrum answered 17/4, 2013 at 9:28 Comment(0)
Q
2

Or another possibility is to create Dialog as follow:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));
Quadrivalent answered 1/12, 2015 at 7:11 Comment(0)
S
1

After taking a look at the API, you can pass the dialog your activity or getActivity if you're in a fragment, then forcefully clean it up with dialog.dismiss() in the return methods to prevent leaks.

Though it is not explicitly stated anywhere I know, it seems you are passed back the dialog in the OnClickHandlers just to do this.

Suannesuarez answered 16/12, 2014 at 13:27 Comment(0)
W
1

If your Dialog is creating on the adapter:

Pass the Activity to the Adapter Constructor:

adapter = new MyAdapter(getActivity(),data);

Receive on the Adapter:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

Now you can use on your Builder

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);
Whereby answered 14/8, 2019 at 23:53 Comment(0)
W
1

Guys I got a simple cheat sheet. create a file give it any name then in it write this code

fun Context.alertdialog(context: Context, msg: String, icon: Drawable, title:String){
    val alertDialog = AlertDialog.Builder(context)
    alertDialog.setIcon(icon)
        .setTitle(title)
        .setMessage(msg)
    alertDialog.show()
}

now when you need to show an alert dialog only use this method anywhere

requireActivity().alertdialog(requireContext(), resources.getString(R.string.pass_title),
                resources.getDrawable(R.drawable.pass_ic_name), "title")

Goodluck for Kotlin

Wilden answered 17/6, 2020 at 7:37 Comment(0)
C
1

What worked for me was to pass the activity instead of the context.

I wanted a custom layout for my dialog, but to keep my code separate, I created it in a separate Class, else I would have to copy and paste that chunk of code into every activity where I want to use the dialog.

Solution explains my situation but it gives the core solution:

  1. As I was using a ViewAdapter I initialised the adapter with the Activity (not context ex. ->[kotlin] activity: Activity) as a parameter -> ex. [kotlin] this@MainActivity
  2. Then I passed that parameter to the Viewholder
  3. After which passing it again to the class that will inflate the Dialog.

Use the activity[optional name]: Activity[mandatory type] every where until it gets to the dialog you want to inflate

Its a lot of passing around, but it does make more sense over copy and pasting the same code everywhere

Coypu answered 28/8, 2020 at 13:41 Comment(0)
W
0

Here is how I resolved same error for my application:
Adding the following line after creating the dialog:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

You will not need to acquire a context. This is particularly useful if you are popping up another dialog over current popped up dialog. Or when it's not convenient to get a context.

Hope this can help you with your app development.

David

Wolfhound answered 5/8, 2019 at 22:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.