Having threads to do some heavy lifting and long processing in the background is pretty standard stuff. Very often you would want to notify or prompt the user after the background task has finished by displaying a Dialog.
The displaying of the Dialog has to happen on the UI thread, so you would do that either in the Handler object for the thread or in the onPostExecute method of an AsyncTask (which is a thread as well, just an easier way of implementing it). That is a textbook way of doing this and you would think that pretty much nothing wrong could go with this.
Surprisingly I found out that something CAN actually go wrong with this. After Google updated the Android Market and started giving crash reports to the developers I received the following exception:
android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@447a6748 is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:468)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.view.Window$LocalWindowManager.addView(Window.java:424)
at android.app.Dialog.show(Dialog.java:239)
at android.app.Activity.showDialog(Activity.java:2488)
…
at android.os.Handler.dispatchMessage(Handler.java:99)
…
I only got a couple of these exceptions from thousands of installs, so I knew that was not anything that happens regularly or that it was easy to replicate.
Looking at the stack trace above it gives us a pretty good idea why it failed. It started in the Handler object, which naturally was called by a background thread after it finished its processing. The Handler instance tried to show a Dialog and before it could show it, it tried to set the View for it and then it failed with:
android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@447a6748 is not valid; is your activity running?
The 447a6748 number is just a memory address of an object that no longer exists.
Note- do not get hung up on the exact number. It would be different with every execution.
Now we know why the application crashed, the only thing left is to figure out what caused it?
We know that background threads execute independently of the main UI thread. That means that the user could be interacting with the application during the time that the thread is doing its work under the covers. Well, what happens if the user hits the “Back” button on the device while the background thread is running and what happens to the Dialog that this thread is supposed to show? Well, if the timing is right the application will most likely crash with the above described error.
In other words what happens is that the Activity will be going through its destruction when the background thread finishes its work and tries to show a Dialog.
In this case it is almost certain that this should have been handled by the Virtual Machine. It should have recognized the fact that the Activity is in the process of finishing and not even attempted to show the Dialog. This is an oversight of the Google developers and it will probably be fixed some time in the future, but in the meantime the burden is on us to take care of this.
The fix to this is pretty simple. Just test if the Activity is going through its finishing phase before displaying the Dialog:
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DISPLAY_DLG:
if (!isFinishing()) {
showDialog(MY_DIALOG);
}
break;
}
}
};
Hey Thanks….
I was finishing activity just after the call to AsyncTask thats why exception was getting fired.
coz there was no activity to show dialog.
anyways thanks for guiding…
great!
Thanks! Mine is 4 out of 1000 installs to be exact.
I’ve found another one. The same message (during testing of course) is reasoned by the fact that I’m running the activity which should start the dialog in a tabbed Host.
In that case you’ve to write
xyz = new Dialog (getParent()) instead of
new Dialog (this)
regards
Michael
@Michael, bingo – just started having the same issue after switching to tabs.
Many thanks!
Thanks man!!
Thank you for this information. I put it into work just now. I hope this helps the few users that are reporting the crash. How annoying!
Thank you very much,
Joshua
Thank you Man
Thanks a lot man. Works for me =D
You could put an extra check, making the activity a WeakReference or your handler a WeakReference. For example, say you have an AsyncTask and you send the handler as parameter:
public class SomeThread extends AsyncTask<Void, Void, HashMap> {
private WeakReference weakHandler;
public SomeThread(WeakReference weakProgressDialog, WeakReference weakHandler) {
this.weakProgressDialog = weakProgressDialog;
this.weakHandler = weakHandler;
}
@Override
protected HashMap doInBackground(Void… params) {
ErrorObject errorObject = null;
HashMap result = null;
String webResponse = DoSomeServerRequest();
if (webResponse != null) {
errorObject = parseError(webResponse);
if (errorObject != null) {
result.put(errorObject, null);
} else {
MyObject myObject = parseMyObject(webResponse);
if (myObject != null) {
result.put(null, myObject);
}
}
return result;
}
errorObject = new ErrorObject();
errorObject.setCode(0);
errorObject.setMessage(“An error has occured”);
result.put(errorObject, null);
return result;
}
@Override
protected void onPostExecute(HashMap result) {
ProgressDialog progressDialog = weakProgressDialog.get();
if (progressDialog != null) {
progressDialog.dismiss();
}
if (result != null) {
for (Map.Entry resultEntries : result.entrySet()) {
ErrorObject errorObject = resultEntries.getKey();
MyObject myObject = resultEntries.getValue();
Message msg = new Message();
Bundle b = new Bundle();
if (errorObject != null) {
b.putSerializable(“error”, errorObject);
} else if (domainsList != null) {
b.putSerializable(“myObject”, myObject);
}
msg.setData(b);
Handler myHandler = weakHandler.get();
if (myHandler != null) {
myHandler.sendMessage(msg);
}
}
}
}
}
Sorry, I forgot to mention the usage:
Handler myHandler = new Handler() {
// Handler implementation
};
ProgressDialog progressDialog = ProgressDialog.show(myContext, “”, “Loading. Please wait…”, true);
WeakReference weakProgressDialog = new WeakReference(progressDialog);
WeakReference weakHandler = new WeakReference(myHandler);
SomeThread someThread = new SomeThread(weakProgressDialog, weakHandler)
someThread.execute();
Perfect! Thanks.
In my case error occurred because the dialog show was invoked during screen rotation. I will put your check.
Thanks
Hi. Intesting post. But can u help me? I have two classes: 1 is activity and 2 is non-activity class where i have create different Dialogs. Then i test connection from activity class – all works fine, but when i try to check connection on button back from 3 activity (in theory ot might be bring me back to 1 activity) my dialog dont appear and all app is crashed! Can i use urs code in this case and how? Thanks.
PS Sorry for my bad English π
@Salmpy,
I am not sure I understand what you are trying to do.
But if you are trying to display dialogs from classes that do not inherit from Activity, you need to pass in an Activity context.
So basically you can either have a member variable in the non Activity class to hold a reference to your Activity context, or pass the activity context in a method call (as a parameter). If that is what you are looking for and need more explanation, let me know.
Thanks! π
Hi,
Thanks for that. I am a little worried about the lack of synchronized() here though. In the following case it can still go wrong (assume background thread running):
– ifFinishing() == False
– Thread switch to UI thread
– call to finish()
– Thread switch back to background thread
– dialog.show()
Therefore, both the ifFinishing() and finish() should be surrounded by a synchronized() clause. This thread switch is unlikely to happen right at that point, but it’s nonetheless undesirable.
@Aert — synchronized() is not necessary here. All of this code runs on the main UI thread: ifFinishing() and dialog.show() are called in a Handler’s message processing code, so are executed from the UI thread’s event loop.
@Dimitar — your site design is a little non-intuitive. You should move the captcha above the submit button. π
hi,
I am creating a dialog from Non-activity class having a reference to activity. I have following code …
MyNonActivityClass{
//other code here
public static AlertDialog dialog;
private void showErrorDialog(String msg) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(“Error”).setMessage(msg).setCancelable(false).setPositiveButton(“Ok”, listener);
// Log.i(tag, “dialog created”);
context.runOnUiThread(new Runnable() {
@Override
public void run() {
UIManager.errorDialog = builder.create();
if (!context.isFinishing(){
context.showDialog(UIManager.ERROR_DIALOG_ID/* , null */);
}else{
Log.i(tag, “can’t display dialog”);
}
}
});
}
}
I was getting this error before I put this check (!isFinishing()) in second app launch on OK button. Error is now gone but so do the Dialog as it always goes in else part (“cant’t display dialog”).
I am not sure why my activity is being destroyed/paused as I am not pressing back button.
thanks.
hi,
I have just notices, when I finish my activity by calling finish(), it doesn’t gets destroyed properly I believe as when press and hold Home key I can see my activity in list.
What could be wrong with finish()??
@Leo,
Pressing and holding the home button gives you the recently run applications not the currently running applications. Your app is in the list because you had recently started it, but it is not necessarily running. So this behavior is normal.
About your other question, please take a look at the Activity lifecycle:
http://developer.android.com/reference/android/app/Activity.html
There is no guarantee that the Activity will always be available to you even if you did not call “finish()” on it.
It is hard to say what is going wrong with your application from this small snippet. It looks like your background task takes too long and the Activity is being destroyed before the thread finishes its job.
Thank you ~ !
Thank you ~!
tnks a lot
thank you very much
thank you man!!
Such a simple and complete explanation for such an irritating issue. Saved my day.. Thanks buddy… π
Pingback:Bug fix?token android.os.BinderProxy@405a3ce0 is not valid; is your activity running? | SignalSiteMap???
thats what i was looking for…
Hi!!
thanks a lot π
it work for me, and i used this code, this is the similar your example:
if(!((Activity) context).isFinishing()){
showDialog();
}
It’s remarkable designed for me to have a website,
which is valuable for my experience. thanks admin
Thanks man:)
that’s working…. thanks π
I am already using same approach to show dialog.
private void showAlertDialog(Activity activity) {
Handler handle = new Handler(Looper.getMainLooper());
if (handle != null) {
handle.post(new Runnable() {
@Override
public void run() {
if (activity != null && !activity.isFinishing()) {
activity.showDialog(DIALOG_ID);
}
}
});
}
}
Still I get error at this line “activity.showDialog(DIALOG_ID);” and this is not always. It sometimes happens. Any idea how can I solve this.
Nice article
Asynctask will do the trick without putting much effort in it.
FATAL EXCEPTION: main
Process: com.example.abhishek_pc.googlelogin, PID: 1683
android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@42b646e0 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:769)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:278)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at android.app.Dialog.show(Dialog.java:289)
at com.example.abhishek_pc.myapp2.BackgroundTask.onPostExecute(BackgroundTask.java:127)
at com.example.abhishek_pc.myapp2.BackgroundTask.onPostExecute(BackgroundTask.java:24)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Hey I am getting this error when I click on butto but it saves the values in database and app crashes any one can help me
code part
protected void onPostExecute(String result) {
if (result.equals(“Registration Success…”)){
Toast.makeText(ctx,result,Toast.LENGTH_LONG).show();
}
else
{
alertDialog.setMessage(result);
alertDialog.show();
}
How can we reproduce this type of crash which appears due to displaying dialog box in which Activity triggers an AsyncTask that tries to display a dialog when it is finished, but the user navigates back from the Activity before the task is completed.