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;
    }
  }
};
Android – Displaying Dialogs From Background Threads

37 thoughts on “Android – Displaying Dialogs From Background Threads

  • March 10, 2011 at 6:03 am
    Permalink

    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…

  • May 24, 2011 at 2:03 am
    Permalink

    great!

  • May 24, 2011 at 11:08 pm
    Permalink

    Thanks! Mine is 4 out of 1000 installs to be exact.

  • July 11, 2011 at 12:03 pm
    Permalink

    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

  • August 19, 2011 at 4:19 am
    Permalink

    Many thanks!

  • September 29, 2011 at 4:43 am
    Permalink

    Thanks man!!

  • October 20, 2011 at 9:54 pm
    Permalink

    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

  • November 6, 2011 at 1:36 pm
    Permalink

    Thank you Man

  • November 20, 2011 at 9:37 pm
    Permalink

    Thanks a lot man. Works for me =D

  • November 22, 2011 at 2:10 am
    Permalink

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

  • November 22, 2011 at 10:36 am
    Permalink

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

  • January 2, 2012 at 4:04 pm
    Permalink

    Perfect! Thanks.

  • January 14, 2012 at 9:11 am
    Permalink

    In my case error occurred because the dialog show was invoked during screen rotation. I will put your check.
    Thanks

  • January 30, 2012 at 3:00 am
    Permalink

    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 πŸ™‚

  • January 31, 2012 at 10:24 pm
    Permalink

    @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.

  • February 9, 2012 at 9:59 am
    Permalink

    Thanks! πŸ™‚

  • March 2, 2012 at 3:04 am
    Permalink

    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.

  • March 30, 2012 at 6:20 am
    Permalink

    @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. πŸ™‚

  • April 2, 2012 at 12:31 pm
    Permalink

    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.

  • April 2, 2012 at 1:09 pm
    Permalink

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

  • April 2, 2012 at 1:45 pm
    Permalink

    @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.

  • April 12, 2012 at 2:22 am
    Permalink

    Thank you ~ !

  • April 12, 2012 at 4:46 am
    Permalink

    Thank you ~!

  • April 25, 2012 at 8:14 am
    Permalink

    tnks a lot

  • June 5, 2012 at 6:33 am
    Permalink

    thank you man!!

  • January 24, 2013 at 2:57 am
    Permalink

    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???

  • February 27, 2014 at 12:20 am
    Permalink

    thats what i was looking for…

  • April 2, 2014 at 1:29 pm
    Permalink

    Hi!!
    thanks a lot πŸ˜€
    it work for me, and i used this code, this is the similar your example:

    if(!((Activity) context).isFinishing()){
    showDialog();
    }

  • November 19, 2014 at 2:49 am
    Permalink

    Thanks man:)

  • February 9, 2015 at 9:32 am
    Permalink

    that’s working…. thanks πŸ™‚

  • July 30, 2015 at 8:32 am
    Permalink

    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.

  • April 6, 2016 at 3:05 am
    Permalink

    Nice article

  • March 3, 2017 at 9:52 am
    Permalink

    Asynctask will do the trick without putting much effort in it.

Leave a Reply

Your email address will not be published. Required fields are marked *


*