-1

I've developed an Android 2.2 application and I get only one time this error:

java.lang.IllegalArgumentException: View not attached to window manager

This error occur when I dismiss ProgressDialog. This dialog is on an AsyncTask. Here is my code:

private class LoadGatesAsyncTask extends AsyncTask<Void, Void, Boolean>
{
    private Context mContext;
    private ArrayList<Gate> mGatesList;
    private ProgressDialog mLoadingDialog;

    public LoadGatesAsyncTask(Context context)
    {
        this.mContext = context;
        mLoadingDialog = new ProgressDialog(mContext);
        mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mLoadingDialog.setMessage(getString(R.string.msg_loading_gates));
        mLoadingDialog.setCancelable(false);
        mLoadingDialog.show();
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Boolean doInBackground(Void... params)
    {
        Boolean result = false;

        try
        {
            [ ... ]
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return result;
    }

    @Override
    protected void onPostExecute(Boolean result)
    {
        super.onPostExecute(result);

        if (result)
        {
            [ ... ]

            mLoadingDialog.dismiss();
        }
        else
        {
            mLoadingDialog.dismiss();
            Toast toast = Toast.makeText(mContext,
                    getString(R.string.msg_error_loading_gates),
                    Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.CENTER, 
                    toast.getXOffset() / 2,
                    toast.getYOffset() / 2);

            toast.show();
        }
    }

}

How can avoid this error programmatically? Is there any check that I could do to avoid dismiss it if it isn't attached to window manager?

Michal
  • 15,429
  • 10
  • 73
  • 104
VansFannel
  • 45,055
  • 107
  • 359
  • 626

4 Answers4

4

are you instantiating LoadGatesAsyncTask in OnCreate?

If so move the loadingDialog instantiation to OnPreExecute rather than in the Constructor.

nandeesh
  • 24,740
  • 6
  • 69
  • 79
  • No, it is instantiated on onResume. – VansFannel Aug 28 '12 at 14:34
  • You can only attach a window only after all the Activity has been shown. This happens only after onresume. So you can show dialogs only after Onresume has finished being executed – nandeesh Aug 28 '12 at 15:25
2

You could add the check:

if(mLoadingDialog.isShowing()){
   mLoadingDialog.dismiss();
}
ekholm
  • 2,543
  • 18
  • 18
2

You are initializing this ProgressDialog in constructor, not in onPreExecute() and that is wrong because you are dismissing the ProgressDialog in onPostExecute, you need to do it on the same UI thread.

If you initialize the object - AsynTask, you get your constructor called. So your ProgressDialog will be shown, but you haven't called .execute() on the AsyncTask yet! So when you're trying to dismiss it, the compilator is finding itself on a different Thread.

EDIT: Clarifying misunderstood statement.

Michal
  • 15,429
  • 10
  • 73
  • 104
  • Sure that the constructor does not run in the same thread as the caller? If so I guess onCreate() runs in the UI thread like onPreExecute() does. – WarrenFaith Aug 28 '12 at 14:44
  • wrong?! If I construct the AsyncTask object from UI thread, don't tell me that the object creation will not be on the UI thread, too! – WarrenFaith Aug 28 '12 at 15:35
  • According to the `threading rules` in the [AsyncTask documentation](http://developer.android.com/reference/android/os/AsyncTask.html) you are wrong: `The task instance must be created on the UI thread` Sorry. – WarrenFaith Aug 28 '12 at 16:37
  • `you need to do it on the GUI thread aka - NOT in constructor` is pretty hard to misinterpret. You are suggesting that the constructor is NOT on the GUI thread. And this is simply wrong! And your complete answer is only about GUI thread and constructor... – WarrenFaith Aug 28 '12 at 20:39
  • I didn't answer this question. Anyway you should really read the documentation more carefully. execute() must be called on the UI thread, too. Just because something is called later doesn't mean it is called from another thread. Your last sentence in the answer is wrong, too. There is only one UI thread. You call the constructor, execute(), onPreExecute() and onPostExecute() from the same thread, always the UI Thread! Execute() creates internally a new thread and runs doInBackground() in this thread. I am not sure how familiar you are with threads, but you should read more about the AsyncTask. – WarrenFaith Aug 28 '12 at 21:00
  • To be more precise about the last sentence: It reads wrong, hard to tell what exactly you mean by "different thread". – WarrenFaith Aug 28 '12 at 21:01
  • Ok lets leave this. It seems that we aren't getting anywhere. My last tipp to prevent future problems: never use "different thread" be much much more explicit to improve the understanding. I just re-read the comments and in my feeling you barely answer to what I am asking/saying... I mean so many comments and you just answered my very first question (first comment, first sentence...) – WarrenFaith Aug 29 '12 at 00:37
1

I think the real problem is behind the attached Activity behind the progressDialog,

it's changing to a new reference (instance),

So that the progressDialog.OwnerActivity=null (usually when in rotation onCreate is called)

it's solved by attaching the new recreated Activity to the owner : progressDialog.OwnerActivity = myActivity; (it will be passed a local parameter in your class, in the constructor pass it, like :( here C# android, similar to java.. same idea)

class ProgressDialogAsync: AsyncTask //extends asynctask
{
//used parameters

Activity Activity;

string Title;
string Message;

ProgressDialog AsyncDialog;

public ProgressDialogAsync(Activity Activity, string Title, string Message)
 {    
  this.Title = Title;
  this.Message = Message;
  this.Activity = Activity;
 }


protected override void OnPreExecute()
{
 AsyncDialog = new ProgressDialog(Activity);
}

protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] @params)       {
 //do background operation
}

protected override void OnPostExecute(Java.Lang.Object result)
{
 //do something
 AsyncDialog.OwnerActivity = Activity;
 AsyncDialog.Dismiss();
 base.OnPostExecute(result);
}
AirL
  • 1,887
  • 2
  • 17
  • 17
FadyAro
  • 11
  • 2