Dialog throwing "Unable to add window — token null

2018-12-31 12:58发布

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

24条回答
弹指情弦暗扣
2楼-- · 2018-12-31 13:02

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();
查看更多
高级女魔头
3楼-- · 2018-12-31 13:03

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.

查看更多
浮光初槿花落
4楼-- · 2018-12-31 13:05

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

查看更多
冷夜・残月
5楼-- · 2018-12-31 13:05

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.

查看更多
孤独总比滥情好
6楼-- · 2018-12-31 13:08

You cannot display an application window/dialog through a Context that is not an Activity or Service. Try passing a valid activity reference

查看更多
明月照影归
7楼-- · 2018-12-31 13:09

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.

查看更多
登录 后发表回答