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

隐身守侯 提交于 2019-11-26 01:24:59

问题


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


回答1:


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




回答2:


Using this did not work for me, but MyActivityName.this did. Hope this helps anyone who could not get this to work.




回答3:


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" />



回答4:


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.




回答5:


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:

  • JRockit Mission Control

  • JProbe

  • YourKit

  • AD4J




回答6:


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.




回答7:


in Activity just use:

MyActivity.this

in Fragment:

getActivity();



回答8:


In Activity on click of button showing a dialog box

Dialog dialog = new Dialog(MyActivity.this);

Worked for me.




回答9:


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



回答10:


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

You should pass this@YourActivity instead of applicationContext or baseContext




回答11:


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



回答12:


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.




回答13:


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




回答14:


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




回答15:


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



回答16:


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

Worked for me.

Cheers!




回答17:


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.




回答18:


For future readers, this should help:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}



回答19:


In my case work:

this.getContext();



回答20:


Or another possibility is to create Dialog as follow:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));



回答21:


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.




回答22:


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




回答23:


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.




回答24:


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




回答25:


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



回答26:


android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(getWindow().getDecorView().getRootView().getContext());

builder.setTitle("Confirm");
builder.setMessage("Are you sure you want delete your old account?");

builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog, int which) {
        //Do nothing but close the dialog



        dialog.dismiss();

    }
});

builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

        //Do nothing
        dialog.dismiss();
    }
});

android.support.v7.app.AlertDialog alert = builder.create();
alert.show();


来源:https://stackoverflow.com/questions/5796611/dialog-throwing-unable-to-add-window-token-null-is-not-for-an-application-wi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!