View not attached to window manager crash

Android

Android Problem Overview


I am using ACRA to report app crashes. I was getting a View not attached to window manager error message and thought I had fixed it by wrapping the pDialog.dismiss(); in an if statement:

if (pDialog!=null) 
{
    if (pDialog.isShowing()) 
    {
        pDialog.dismiss();   
    }
}

It has reduced the amount of View not attached to window manager crashes I recieve, but I am still getting some and I am not sure how to solve it.

Error message:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:425)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:327)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:83)
at android.app.Dialog.dismissDialog(Dialog.java:330)
at android.app.Dialog.dismiss(Dialog.java:312)
at com.package.class$LoadAllProducts.onPostExecute(class.java:624)
at com.package.class$LoadAllProducts.onPostExecute(class.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)

Code snippet:

class LoadAllProducts extends AsyncTask<String, String, String> 
{

	/**
	 * Before starting background thread Show Progress Dialog
	 * */
	@Override
	protected void onPreExecute() 
	{
		super.onPreExecute();
		pDialog = new ProgressDialog(CLASS.this);
		pDialog.setMessage("Loading. Please wait...");
		pDialog.setIndeterminate(false);
		pDialog.setCancelable(false);
		pDialog.show();
	}

	/**
	 * getting All products from url
	 * */
	protected String doInBackground(String... args) 
	{
		// Building Parameters
		doMoreStuff("internet");
		return null;
	}


	/**
	 * After completing background task Dismiss the progress dialog
	 * **/
	protected void onPostExecute(String file_url) 
	{
		 // dismiss the dialog after getting all products
		 if (pDialog!=null) 
		 {
	            if (pDialog.isShowing()) 
	            {
	                pDialog.dismiss();   //This is line 624!    
	            }
		 }
		 something(note);
	}
}

Manifest:

    <activity
        android:name="pagename.CLASS" 
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"            
        android:label="@string/name" >
    </activity>

What am I missing to stop this crash from happening?

Android Solutions


Solution 1 - Android

How to reproduce the bug:

  1. Enable this option on your device: Settings -> Developer Options -> Don't keep Activities.
  2. Press Home button while the AsyncTask is executing and the ProgressDialog is showing.

The Android OS will destroy an activity as soon as it is hidden. When onPostExecute is called the Activity will be in "finishing" state and the ProgressDialog will be not attached to Activity.

How to fix it:

  1. Check for the activity state in your onPostExecute method.
  2. Dismiss the ProgressDialog in onDestroy method. Otherwise, android.view.WindowLeaked exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.

Try this fixed code:

public class YourActivity extends Activity {
 
    private void showProgressDialog() {
        if (pDialog == null) {
            pDialog = new ProgressDialog(StartActivity.this);
            pDialog.setMessage("Loading. Please wait...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(false);
        }
        pDialog.show();
    }
    
    private void dismissProgressDialog() {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }

    @Override
    protected void onDestroy() {
        dismissProgressDialog();
        super.onDestroy();
    }

    class LoadAllProducts extends AsyncTask<String, String, String> {

        // Before starting background thread Show Progress Dialog
        @Override
        protected void onPreExecute() {
            showProgressDialog();
        }

        //getting All products from url
        protected String doInBackground(String... args) {
            doMoreStuff("internet");
            return null;
        }

        // After completing background task Dismiss the progress dialog
        protected void onPostExecute(String file_url) {
            if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17
                return;
            }
            dismissProgressDialog();
            something(note);
        }
    }
}

Solution 2 - Android

Issue could be that the Activity have been finished or in progress of finishing.

Add a check isFinishing , and dismiss dialog only when this is false

if (!YourActivity.this.isFinishing() && pDialog != null) {
    pDialog.dismiss();
}

isFinishing : Check to see whether this activity is in the process of finishing,either because you called finish on it or someone else has requested that it finished.

Solution 3 - Android

For Dialog created in a Fragment, I use the following code:

ProgressDialog myDialog = new ProgressDialog(getActivity());
myDialog.setOwnerActivity(getActivity());
...
Activity activity = myDialog.getOwnerActivity();
if( activity!=null && !activity.isFinishing()) {
    myDialog.dismiss();
}

I use this pattern to deal with the case when a Fragment may be detached from the Activity.

Solution 4 - Android

See how the Code is working here:

After calling the Async task, the async task runs in the background. that is desirable. Now, this Async task has a progress dialog which is attached to the Activity, if you ask how to see the code:

pDialog = new ProgressDialog(CLASS.this);

You are passing the Class.this as context to the argument. So the Progress dialog is still attached to the activity.

Now consider the scenario: If we try to finish the activity using the finish() method, while the async task is in progress, is the point where you are trying to access the Resource attached to the activity ie the progress bar when the activity is no more there.

Hence you get:

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

Solution to this:

  1. Make sure that the Dialog box is dismissed or canceled before the activity finishes.

  2. Finish the activity, only after the dialog box is dismissed, that is the async task is over.

Solution 5 - Android

Based on @erakitin answer, but also compatible for Android versions < API level 17. Sadly Activity.isDestroyed() is only supported since API level 17, so if you're targeting an older API level just like me, you'll have to check it yourself. Haven't got the View not attached to window manager exception after that.

Example code

public class MainActivity extends Activity {
    private TestAsyncTask mAsyncTask;
    private ProgressDialog mProgressDialog;
    private boolean mIsDestroyed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (condition) {
            mAsyncTask = new TestAsyncTask();
            mAsyncTask.execute();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) {
            Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show();
            return;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mIsDestroyed = true;

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

    public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> {    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff..");
        }

        @Override
        protected AsyncResult doInBackground(Void... arg0) {
            // Do long running background stuff
            return null;
        }

        @Override
        protected void onPostExecute(AsyncResult result) {
            // Use MainActivity.this.isDestroyed() when targeting API level 17 or higher
            if (mIsDestroyed)// Activity not there anymore
                return;

            mProgressDialog.dismiss();
            // Handle rest onPostExecute
        }
    }
}

Solution 6 - Android

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

    if(pDialog != null)
        pDialog .dismiss();
    pDialog = null;
}

refer this.

Solution 7 - Android

Override onConfigurationChanged and dismiss progress dialog. If progress dialog is created in portrait and dismisses in landscape then it will throw View not attached to window manager error.

Also stop the progress bar and stop the async task in onPause(), onBackPressed and onDestroy method.

if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){

    asyncTaskObj.cancel(true);

}

Solution 8 - Android

Override onDestroy of the Activity and Dismiss your Dialog & make it null

protected void onDestroy ()
	{
		if(mProgressDialog != null)
			if(mProgressDialog.isShowing())
				mProgressDialog.dismiss();
		mProgressDialog= null;
	}

Solution 9 - Android

Firstly,the crash reason is decorView's index is -1,we can knew it from Android source code ,there is code snippet: >class:android.view.WindowManagerGlobal > >file:WindowManagerGlobal.java

private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
//here, view is decorView,comment by OF
        if (required && index < 0) {
            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
        }
        return index;
    }

so we get follow resolution,just judge decorView's index,if it more than 0 then continue or just return and give up dismiss,code as follow:

try {
            Class<?> windowMgrGloable = Class.forName("android.view.WindowManagerGlobal");
            try {
                Method mtdGetIntance = windowMgrGloable.getDeclaredMethod("getInstance");
                mtdGetIntance.setAccessible(true);
                try {
                    Object windownGlobal = mtdGetIntance.invoke(null,null);
                    try {
                        Field mViewField = windowMgrGloable.getDeclaredField("mViews");
                        mViewField.setAccessible(true);
                        ArrayList<View> mViews = (ArrayList<View>) mViewField.get(windownGlobal);
                        int decorViewIndex = mViews.indexOf(pd.getWindow().getDecorView());
                        Log.i(TAG,"check index:"+decorViewIndex);
                        if (decorViewIndex < 0) {
                            return;
                        }
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if (pd.isShowing()) {
            pd.dismiss();
        }

Solution 10 - Android

Overide the dismiss() method like this:

@Override
public void dismiss() {
    Window window = getWindow();
    if (window == null) {
        return;
    }
    View decor = window.getDecorView();
    if (decor != null && decor.getParent() != null) {
        super.dismiss();
    }
}

To reproduce the issue, just finish activity before dismiss dialog.

Solution 11 - Android

I got a way to reproduce this exception.

I use 2 AsyncTask. One do long task and another do short task. After short task complete, call finish(). When long task complete and call Dialog.dismiss(), it crashes.

Here's my sample code:

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate");

        new AsyncTask<Void, Void, Void>(){
            @Override
            protected void onPreExecute() {
                mProgressDialog = ProgressDialog.show(MainActivity.this, "", "plz wait...", true);
            }

            @Override
            protected Void doInBackground(Void... nothing) {
                try {
                    Log.d(TAG, "long thread doInBackground");
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                Log.d(TAG, "long thread onPostExecute");
                if (mProgressDialog != null && mProgressDialog.isShowing()) {
                    mProgressDialog.dismiss();
                    mProgressDialog = null;
                }
                Log.d(TAG, "long thread onPostExecute call dismiss");
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        new AsyncTask<Void, Void, Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    Log.d(TAG, "short thread doInBackground");
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Log.d(TAG, "short thread onPostExecute");
                finish();
                Log.d(TAG, "short thread onPostExecute call finish");
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

You can try this and find out what is the best way to fix this issue. From my study, there are at least 4 ways to fix it:

  1. @erakitin's answer: call isFinishing() to check activity's state
  2. @Kapé's answer: set flag to check activity's state
  3. Use try/catch to handle it.
  4. Call AsyncTask.cancel(false) in onDestroy(). It will prevent the asynctask to execute onPostExecute() but execute onCancelled() instead.
    Note: onPostExecute() will still execute even you call AsyncTask.cancel(false) on older Android OS, like Android 2.X.X.

You can choose the best one for you.

Solution 12 - Android

best solution. Check first context is activity context or application context if activity context then only check activity is finished or not then call dialog.show() or dialog.dismiss();

> See sample code below... hope it will be helpful ! > > Display dialog

if (context instanceof Activity) {
   if (!((Activity) context).isFinishing())
     dialog.show();
}

> Dismiss dialog

if (context instanceof Activity) {
       if (!((Activity) context).isFinishing())
         dialog.dismiss();
    }

If you want to add more checks then add dialog.isShowing() or dialog !-null using && condition.

Solution 13 - Android

Check if the owner activity is still alive:

if (dialog.getOwnerActivity() ==null || dialog.getOwnerActivity().isFinishing()) {
    dialog.dismiss();
}

Solution 14 - Android

This issue is because of your activity gets finished before the dismiss function gets called. Handle the exception and check your ADB log for the exact reason.

/**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) {
    try {
         if (pDialog!=null) {
            pDialog.dismiss();   //This is line 624!    
         }
    } catch (Exception e) {
        // do nothing
    }
     something(note);
}

Solution 15 - Android

May be you initialize pDialog globally, Then remove it and intialize your view or dialog locally.I have same issue, I have done this and my issue is resolved. Hope it will work for u.

Solution 16 - Android

we have also dismiss our dialog on onPause method or onDestroy method

@Override
protected void onPause() {
    super.onPause();
    dialog.dismiss();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    dialog.dismiss();
}

Solution 17 - Android

You can try to check this solution or try the below solution.

if (pDialog instanceof Activity && !((Activity) mContext).isFinishing())
		pDialog.show();

Solution 18 - Android

I'm using this simple extension function to check whether the activity is destroyed or not.

    protected fun Activity?.isNoMore(): Boolean {
        return this?.let {
            isFinishing || isDestroyed
        } ?: true
    }

Use it in your activity as mentioned below.

if (!isNoMore()) {
//show your dialog. Also, make the null check for dialog object.
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHowliView Question on Stackoverflow
Solution 1 - AndroiderakitinView Answer on Stackoverflow
Solution 2 - AndroidLibinView Answer on Stackoverflow
Solution 3 - AndroidTeng-pao YuView Answer on Stackoverflow
Solution 4 - AndroidKailasView Answer on Stackoverflow
Solution 5 - AndroidKapéView Answer on Stackoverflow
Solution 6 - AndroidMeghnaView Answer on Stackoverflow
Solution 7 - AndroidPratapi Hemant PatelView Answer on Stackoverflow
Solution 8 - AndroidsuryaView Answer on Stackoverflow
Solution 9 - AndroidaolphnView Answer on Stackoverflow
Solution 10 - AndroidthundertrickView Answer on Stackoverflow
Solution 11 - AndroidYueh-Ming ChienView Answer on Stackoverflow
Solution 12 - AndroidYogesh RathiView Answer on Stackoverflow
Solution 13 - AndroidGil SHView Answer on Stackoverflow
Solution 14 - AndroidRajiv ManivannanView Answer on Stackoverflow
Solution 15 - AndroidShashwat GuptaView Answer on Stackoverflow
Solution 16 - Androidtarun bholaView Answer on Stackoverflow
Solution 17 - AndroidMohamedHarmoushView Answer on Stackoverflow
Solution 18 - AndroidVishal NaikawadiView Answer on Stackoverflow