115

I am having some of the following exceptions:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:191)
at android.view.Window$LocalWindowManager.updateViewLayout(Window.java:428)
at android.app.Dialog.onWindowAttributesChanged(Dialog.java:596)
at android.view.Window.setDefaultWindowFormat(Window.java:1013)
at com.android.internal.policy.impl.PhoneWindow.access$700(PhoneWindow.java:86)
at com.android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.java:1951)
at com.android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.java:1889)
at android.view.ViewRoot.performTraversals(ViewRoot.java:727)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4338)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)

I have googled it and see that it has something to do with popups and turning the screen, but there is no reference to my code.

The questions are:

  1. is there a way to find out exactly when this issue is happening?
  2. other than turning the screen, is there another event or action that triggers this error?
  3. how do I prevent this to happen?
Usman Kurd
  • 7,212
  • 7
  • 57
  • 86
Daniel Benedykt
  • 6,496
  • 12
  • 51
  • 73
  • 1
    See if you can explain how the activity is described in the manifest and what activity is on the screen when the error occurs. See if you can chip away your problem into a minimal testcase. – Josh Lee Feb 09 '10 at 10:54
  • Maybe you are trying to modify your view before `View#onAttachedToWindow()` has been called? – Alex Lockwood Jun 26 '13 at 01:58

14 Answers14

163

I had this issue where on a screen orientation change, the activity finished before the AsyncTask with the progress dialog completed. I seemed to resolve this by setting the dialog to null onPause() and then checking this in the AsyncTask before dismissing.

@Override
public void onPause() {
    super.onPause();

    if ((mDialog != null) && mDialog.isShowing())
        mDialog.dismiss();
    mDialog = null;
}

... in my AsyncTask:

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
            true);
}

protected void onPostExecute(Object result) {
   if ((mDialog != null) && mDialog.isShowing()) { 
        mDialog.dismiss();
   }
}
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
johnnyblizzard
  • 1,646
  • 1
  • 11
  • 2
  • 13
    @YekhezkelYovel the AsyncTask is running in a thread which survives the activity restart and may hold references to the now dead Activity and its Views (this is a effectively a memory leak, albeit probably a short term one - depends how long the task takes to complete). The solution above works fine, if you're happy to accept a short term memory leak. The recommended approach is to cancel() any running AsyncTask's when the Activity is paused. – Stevie May 31 '13 at 13:30
9

After a fight with this issue, I finally end up with this workaround:

/**
 * Dismiss {@link ProgressDialog} with check for nullability and SDK version
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissProgressDialog(ProgressDialog dialog) {
    if (dialog != null && dialog.isShowing()) {

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();

            // if the Context used here was an activity AND it hasn't been finished or destroyed
            // then dismiss it
            if (context instanceof Activity) {

                // Api >=17
                if (!((Activity) context).isFinishing() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isDestroyed()) {
                            dismissWithExceptionHandling(dialog);
                        }
                    } else { 
                        // Api < 17. Unfortunately cannot check for isDestroyed()
                        dismissWithExceptionHandling(dialog);
                    }
                }
            } else
                // if the Context used wasn't an Activity, then dismiss it too
                dismissWithExceptionHandling(dialog);
        }
        dialog = null;
    }
}

/**
 * Dismiss {@link ProgressDialog} with try catch
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissWithExceptionHandling(ProgressDialog dialog) {
    try {
        dialog.dismiss();
    } catch (final IllegalArgumentException e) {
        // Do nothing.
    } catch (final Exception e) {
        // Do nothing.
    } finally {
        dialog = null;
    }
}

Sometimes, good exception handling works well if there wasn't a better solution for this issue.

Community
  • 1
  • 1
blueware
  • 5,205
  • 1
  • 40
  • 60
6

If you have an Activity object hanging around, you can use the isDestroyed() method:

Activity activity;

// ...

if (!activity.isDestroyed()) {
    // ...
}

This is nice if you have a non-anonymous AsyncTask subclass that you use in various places.

shawkinaw
  • 3,190
  • 2
  • 27
  • 30
3

I am using a custom static class which makes- shows and hides a dialog. this class is being used by other activities too not only one activiy. Now the problem you described also appeared to me and i have stayed overnight to find a solution..

Finally i present you the solution!

if you want to show or dismiss a dialog and you dont know which activity initiated the dialog in order to touch it then the following code is for you..

 static class CustomDialog{

     public static void initDialog(){
         ...
         //init code
         ...
     }

      public static void showDialog(){
         ...
         //init code for show dialog
         ...
     }

     /****This is your Dismiss dialog code :D*******/
     public static void dismissProgressDialog(Context context) {                
            //Can't touch other View of other Activiy..
            //http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-android
            if ( (progressdialog != null) && progressdialog.isShowing()) {

                //is it the same context from the caller ?
                Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());

                Class caller_context= context.getClass();
                Activity call_Act = (Activity)context;
                Class progress_context= progressdialog.getContext().getClass();

                Boolean is_act= ( (progressdialog.getContext()) instanceof  Activity )?true:false;
                Boolean is_ctw= ( (progressdialog.getContext()) instanceof  ContextThemeWrapper )?true:false;

                if (is_ctw) {
                    ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
                    Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() ==  call_Act )?true:false;

                    if (is_same_acivity_with_Caller){
                        progressdialog.dismiss();
                        progressdialog = null;
                    }
                    else {
                        Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
                        progressdialog = null;
                    }
                }


            }
        } 

 }
aimiliano
  • 1,105
  • 2
  • 12
  • 18
2

Above solution didn't work for me. So what I did is take ProgressDialog as globally and then add this to my activity

@Override
    protected void onDestroy() {
        if (progressDialog != null && progressDialog.isShowing())
            progressDialog.dismiss();
        super.onDestroy();
    }

so that in case if activity is destroyed then the ProgressDialog will also be destroy.

Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82
0

Or Simply you Can add

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}

which will make the ProgressDialog to not cancel-able

Nidhish Krishnan
  • 20,593
  • 6
  • 63
  • 76
Sarith Vasu
  • 81
  • 1
  • 5
0

according to the code of the windowManager (link here), this occurs when the view you are trying to update (which probably belongs to a dialog, but not necessary) is no longer attached to the real root of the windows.

as others have suggested, you should check the status of the activity before performing special operations on your dialogs.

here's the relavant code, which is the cause to the problem (copied from Android source code) :

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams
            = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);

    synchronized (this) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots[index];
        mParams[index] = wparams;
        root.setLayoutParams(wparams, false);
    }
}

private int findViewLocked(View view, boolean required) {
        synchronized (this) {
            final int count = mViews != null ? mViews.length : 0;
            for (int i=0; i<count; i++) {
                if (mViews[i] == view) {
                    return i;
                }
            }
            if (required) {
                throw new IllegalArgumentException(
                        "View not attached to window manager");
            }
            return -1;
        }
    }
android developer
  • 114,585
  • 152
  • 739
  • 1,270
0

For question 1):

Considering that the error message doesn't seem to say which line of your code is causing the trouble, you can track it down by using breakpoints. Breakpoints pause the execution of the program when the program gets to specific lines of code. By adding breakpoints to critical locations, you can determine which line of code causes the crash. For example, if your program is crashing at a setContentView() line, you could put a breakpoint there. When the program runs, it will pause before running that line. If then resuming causes the program to crash before reaching the next breakpoint, you then know that the line that killed the program was between the two breakpoints.

Adding breakpoints is easy if you're using Eclipse. Right click in the margin just to the left of your code and select "Toggle breakpoint". You then need to run your application in debug mode, the button that looks like a green insect next to the normal run button. When the program hits a breakpoint, Eclipse will switch to the debug perspective and show you the line it is waiting at. To start the program running again, look for the 'Resume' button, which looks like a normal 'Play' but with a vertical bar to the left of the triangle.

You can also fill your application with Log.d("My application", "Some information here that tells you where the log line is"), which then posts messages in Eclipse's LogCat window. If you can't find that window, open it up with Window -> Show View -> Other... -> Android -> LogCat.

Hope that helps!

Steve Haley
  • 55,374
  • 17
  • 77
  • 85
  • 7
    The issue is happening on the clients phones, so I dont have an option to debug. Also the issue is happening all the time, just happening sometimes, so dont know how to track it – Daniel Benedykt Mar 08 '10 at 14:27
  • You can still get debugging messages from a phone, if you can get your hands on one. In menu -> settings -> applications -> development, there's an option for USB Debugging. If enabled, you can then plug the phone in and LogCat catches all the normal debugging lines. Other than that... well... the intermittency could be explained by it depending on the state of the program. I suppose you'd have to mess around using the program to see if you could recreate the issue. – Steve Haley Mar 08 '10 at 15:09
  • 4
    As I said before, the issue is happening on a client phone, and I dont have access to it. The client may be on another continent :) – Daniel Benedykt Mar 08 '10 at 16:03
  • There are apps on the market that will email you their logcat. – Tim Green Jun 02 '10 at 12:10
  • 1
    Just so you know you can rotate the emulator by pressing the numpad key 9 – Rob Dec 20 '10 at 15:42
0

My problem was solved by uhlocking the screen rotation on my android the app which was causing me a problem now works perfectly

Roger
  • 1
0

Another option is not to start the async task until the dialog is attached to the window by overriding onAttachedToWindow() on the dialog, that way it is always dismissible.

Nick Palmer
  • 2,589
  • 1
  • 25
  • 34
0

I added the following to the manifest for that activity

android:configChanges="keyboardHidden|orientation|screenLayout"
Lucifer
  • 29,392
  • 25
  • 90
  • 143
Rickey
  • 7,830
  • 1
  • 19
  • 12
0

I think you are trying to show/dismiss your dialog after destroying/finish the activity. So that's how you can handle this scenario

if (dialog?.window?.decorView?.isShown!!) {
    dialog?.dismiss()
    finish()
}
-2

Why not try catch, like this:

protected void onPostExecute(Object result) {
        try {
            if ((mDialog != null) && mDialog.isShowing()) {
                mDialog.dismiss();
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.getMessage(), ex);
        }
    }
Heasen
  • 11
-3

when you declare activity in the manifest you need android:configChanges="orientation"

example:

<activity android:theme="@android:style/Theme.Light.NoTitleBar" android:configChanges="orientation"  android:label="traducción" android:name=".PantallaTraductorAppActivity"></activity>
Cristian
  • 3
  • 1
  • 1
    This tag is required only if developer doesn't want to destroy and recreate the activity by android system. – Ankit Nov 12 '13 at 10:16