Android: ProgressDialog.show()与 getApplicationContext 崩溃

我不明白为什么会这样,这个密码:

mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);

可以正常工作,但是,这个代码:

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

抛出以下异常:

W/WindowManager(  569): Attempted to add window with non-application token WindowToken{438bee58 token=null}.  Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049):    at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049):    at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049):    ... 11 more

知道为什么会发生这种情况吗? 我从 onCreate方法调用它。

141349 次浏览

Which API version are you using? If I'm right about what the problem is then this was fixed in Android 1.6 (API version 4).

It looks like the object reference that getApplicationContext() is returning just points to null. I think you're having a problem similar to one I had in that some of the code in the onCreate() is being run before the window is actually done being built. This is going to be a hack, but try launching a new Thread in a few hundred milliseconds (IIRC: 300-400 seemed to work for me, but you'll need to tinker) that opens your ProgressDialog and starts anything else you needed (eg. network IO). Something like this:

@Override
public void onCreate(Bundle savedInstanceState) {
// do all your other stuff here


new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mProgressDialog = ProgressDialog.show(
YouTube.this.getApplicationContext(), "",
YouTube.this.getString(R.string.loading), true);


// start time consuming background process here
}
}, 1000); // starting it in 1 second
}

I don't think this is a timing issue around a null application context

Try extending Application within your app (or just use it if you already have)

public class MyApp extends Application

Make the instance available as a private singleton. This is never null

private static MyApp appInstance;

Make a static helper in MyApp (which will use the singleton)

    public static void showProgressDialog( CharSequence title, CharSequence message )
{
prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}

BOOM!!

Also, check out android engineer's answer here: WindowManager$BadTokenException

One cause of this error may be trying to display an application window/dialog through a Context that is not an Activity.

Now, i agree, it does not make sense that the method takes a Context param, instead of Activity..

I am using Android version 2.1 with API Level 7. I faced with this (or similar) problem and solved by using this:

Dialog dialog = new Dialog(this);

instead of this:

Dialog dialog = new Dialog(getApplicationContext());

Hope this helps :)

I have implemented Alert Dialog for exception throwing on to the current activitty view.Whenever I had given like this

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

Given same Window Exception.I write code for alert out of onCreate().So simple I used context = this; after setContentView() statement in onCreate() method.Taken context variable as global like Context context;

Code sample is

static Context context;


public void onCreate(Bundle savedInstanceState)  {
super.onCreate(savedInstanceState);




setContentView(R.layout.network);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);


context = this;
.......

Alert Method Sample is

private void alertException(String execMsg){
Log.i(TAG,"in alertException()..."+context);
Log.e(TAG,"Exception :"+execMsg);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......

It works fine for me.Actually I searched for this error on StackOverflow I found this query.After reading all responses of this post, I tried this way so It works .I thought this is a simple solution for overcome the exception.

Thanks, Rajendar

What I did to get around this was to create a base class for all my activities where I store global data. In the first activity, I saved the context in a variable in my base class like so:

Base Class

public static Context myucontext;

First Activity derived from the Base Class

mycontext = this

Then I use mycontext instead of getApplicationContext when creating dialogs.

AlertDialog alertDialog = new AlertDialog.Builder(mycontext).create();

I am creating a map view with itemized overlays. I was creating my itemizedoverlay like this from my mapActivity:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

I found that I would get the "android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application" exception when my itemizedoverlay's onTap method was triggered(when the location is tapped on the mapview).

I found that if I simply passed, 'this' instead of 'getApplicationContext()' to my constructor, the problem went away. This seems to support alienjazzcat's conclusion. weird.

Having read the above answers i found that for my situation the following fixed the issue.

This threw the error

myButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
MyDialogue dialog = new MyDialogue(getApplicationContext());
dialog.show();
}
});

Based on the previous answers that suggested the context was the wrong one, i changed the getApplicationContext() to retrieve the context from the View passed in to the buttons onClick method.

myButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
MyDialogue dialog = new MyDialogue(v.getContext());
dialog.show();
}
});

I don't fully understand the workings of Java so i could be wrong, but I'm guessing that for my specific situation the cause could have been related to the fact that the above snippet was defined in an Abstract Activity class; inherited and used by many Activities, perhaps that contributed to the fact that getApplicationContext() doesn't return a valid context?? (Just a guess).

For me worked changing

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

to

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

Weird thing is that the first one can be found in google tutorial and people get error on this..

For Android 2.2
Use this code:

//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);

instead of this code:

// this code produces an ERROR:
//android.view.WindowManager$BadTokenException:
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);

Remark: My custom dialog is created outside activity.onCreateDialog(int dialogId) method.

Try -

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

For Activities shown within TabActivities use getParent()

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

instead of

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

if you have a problem on groupActivity dont use this. PARENT is a static from the Parent ActivityGroup.

final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);

instead of

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

A dialog is always created and displayed as a part of an Activity. You need to pass in an Activity context instead of the Application context.

http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog

Had a similar problem with (compatibility) Fragments in which using a getActivity() within ProgressDialog.show() crashes it. I'd agree that it is because of timing.

A possible fix:

mContext = getApplicationContext();


if (mContext != null) {
mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}

instead of using

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

Place the mContext as early as possible to give it more time to grab the context. There's still no guarantee that this will work, it just reduces the likelihood of a crash. If it still doesn't work, you'd have to resort to the timer hack (which can cause other timing problems like dismissing the dialog later).

Of course, if you can use this or ActivityName.this, it's more stable because this already points to something. But in some cases, like with certain Fragment architectures, it's not an option.

(For future references)

I think it's because there's differences in Application Context and Activity Context, as explained here: http://www.doubleencore.com/2013/06/context/

Which means that we can't show dialog using Application Context. That's it.

If you're calling ProgressDialog.show() in a fragment, casting the mContext to Activity worked for me.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);

For using dialogs inside activities, do it this way:

private Context mContext;
private AlertDialog.Builder mBuilder;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;


//using mContext here refering to activity context
mBuilder = new AlertDialog.Builder(mContext);
//...
//rest of the code
//...
}

For using dialogs inside fragments, do it this way:

private Context mContext;
private AlertDialog.Builder mBuilder;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
mContext = getActivity();


//using mContext here refering to fragment's hosting activity context
mBuilder = new AlertDialog.Builder(mContext);
//...
//rest of the code
//...
return mRootView;
}

That's it ^_^

This is a common problem. Use this instead of getApplicationContext() That should solve your problem