ProgressDialog : how to prevent Leaked Window
Asked Answered
H

11

50

I'm using ProgressDialog to prevent the user from interacting while the device is downloading stuff from internet.

everything was working fine until my client managed to produce this bug :

"07-06 17:10:50.363: ERROR/WindowManager(8821): Activity android.pixelrain.framework.PixelRainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@463f3e50 that was originally added here
07-06 17:10:50.363: ERROR/WindowManager(8821): android.view.WindowLeaked: Activity android.pixelrain.framework.PixelRainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@463f3e50 that was originally added here
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewRoot.<init>(ViewRoot.java:251)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.Dialog.show(Dialog.java:241)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ProgressDialog.show(ProgressDialog.java:107)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ProgressDialog.show(ProgressDialog.java:90)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftHelper.getDraft(DraftHelper.java:70)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.online.OnlineRetriver.getDraft(OnlineRetriver.java:312)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftButtonGL.loadDraft(DraftButtonGL.java:72)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftButtonGL.isTouched(DraftButtonGL.java:89)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.opengl.views.game.QuickStartGL.touchEnded(QuickStartGL.java:160)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.game.GameHandler.onTouchEvent(GameHandler.java:277)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.opengl.GLSurfaceViewChipmunk.onTouchEvent(GLSurfaceViewChipmunk.java:27)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.View.dispatchTouchEvent(View.java:3765)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1701)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1116)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.Activity.dispatchTouchEvent(Activity.java:2093)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1685)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1802)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.os.Looper.loop(Looper.java:144)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ActivityThread.main(ActivityThread.java:4937)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at java.lang.reflect.Method.invokeNative(Native Method)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at java.lang.reflect.Method.invoke(Method.java:521)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at dalvik.system.NativeStart.main(Native Method)"

and I have no idea how to fix this.

any ideas what causes this and how to solve it ?

The log traces back the error to this line :

    progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);

would it solve the problem if I changed it to this :

this.runOnUiThread(new Runnable() {
            public void run() {
                progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);
            }
        });
Heddie answered 7/7, 2011 at 17:34 Comment(3)
I had the same problem, and it only occured when I was opening a Dialog/ProcessDialog when the activity was paused. Is that the case?Rigamarole
Or may be while changing orientations?Pronuba
Please update the accepted answer to be to use dismissRogelioroger
S
17

The leak comes probably from your PixelRainActivity.staticThis attribute. If you’re keeping a reference to an activity, even after that this activity has been destroyed, you have a memory leak.

The easiest way to fix is to use the application’s Context instead. Change your staticThis = this line in the method onCreate() to staticThis = this.getApplicationContext() and it should work (and change the type of staticThis to Context if this is not already the case)

Stated answered 13/7, 2011 at 0:31 Comment(4)
didn't work for me. I am using progressDialog.show() in Async task's onPreExecute(). and i get: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an applicationTry
In order to create Dialog, you have to pass not Context, but Activity. So, this.getApplicationContext() is not correctCheesewood
According to this, using getApplicationContext will throw an error in this situation: #5797111Postexilian
-1 @Guillaume Brunerie - You have to pass an Activity instance as a context ,bcz that operation is conducted in UI.So passing getApplicationContext() will lead to an exception.Gland
A
119

Use:

progressDialog.dismiss();

in end work

Absolute answered 22/12, 2011 at 11:47 Comment(2)
I was wrongly calling hide and not dismiss(). Thank you.Commutation
To add the the answer: you probably should call progressDialog.dismiss() in onDestroy() (but before calling super.onDestroy())Viminal
S
17

The leak comes probably from your PixelRainActivity.staticThis attribute. If you’re keeping a reference to an activity, even after that this activity has been destroyed, you have a memory leak.

The easiest way to fix is to use the application’s Context instead. Change your staticThis = this line in the method onCreate() to staticThis = this.getApplicationContext() and it should work (and change the type of staticThis to Context if this is not already the case)

Stated answered 13/7, 2011 at 0:31 Comment(4)
didn't work for me. I am using progressDialog.show() in Async task's onPreExecute(). and i get: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an applicationTry
In order to create Dialog, you have to pass not Context, but Activity. So, this.getApplicationContext() is not correctCheesewood
According to this, using getApplicationContext will throw an error in this situation: #5797111Postexilian
-1 @Guillaume Brunerie - You have to pass an Activity instance as a context ,bcz that operation is conducted in UI.So passing getApplicationContext() will lead to an exception.Gland
U
5

There are situations when you have to verify in onDetach or in onDestroy if the progress dialog is still visible. Like so:

@Override
public void onDetach() {
    if (mProgressDialog != null && mProgressDialog.isShowing())
        mProgressDialog.dismiss();
    super.onDetach();
}
Unquestioning answered 22/2, 2017 at 22:33 Comment(0)
H
3

cygnus has a good idea to use showDialog(MY_INT), where MY_INT is just some constant value you choose just to distinguish it from any other similar dialogs you launch that way. You take it down the same way with dismissDialog(MY_INT). Just don't launch it from your onPause method. You may want to do that instead from the the onResume method of the activity the user is going to. Then you override that activity's onCreateDialog method like this:

@Override
protected Dialog onCreateDialog(int id) {
    if(id == MY_INT) {
        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Your message string");
        return progressDialog;
    }
    return super.onCreateDialog(id);
}
Heron answered 1/12, 2011 at 3:29 Comment(0)
T
2

Instead of using ProgressDialog.show(), try using

Activity.showDialog() which should automatically manage the Dialog for you and prevent leaks.

EDIT: When you call showDialog(int), it will trigger Activity.onCreateDialog(int) where you can create the Dialog you want and return the Dialog you want to display.

Thayer answered 7/7, 2011 at 19:6 Comment(1)
but whit Activity.showDialog() I need to pass the an ID to a dialog, how then do display the progress dialog box?Heddie
F
1

I ran into a similar problem with a progress dialog and a background task. The AsyncTask (http://android-developers.blogspot.de/2009/05/painless-threading.html) allowed me to do both much more cleanly and without the leaked window.

Fantasia answered 7/7, 2011 at 21:50 Comment(1)
that link is a dead endTananarive
B
1

If you are using any thread or AsyncTask and downloading stuff from internet and showing progress bar , you should use DialogFragment or cancel progress dialog when Activity get stop also if you are showing progress in Asynctask fist cancel Asynctask and override oncancel callback method and dismiss progress dialogue there.

Window leak in Activity or fragment is actually occurs due to you are trying to add a window and while it shows up it is on the foreground,but when you are pressing the home it gets paused and then gets stopped via the onStop(). So your CustomView remains attached to the window that now has disappeared.Hence according to the system your customView occupied the space which it did not release.

Breadroot answered 3/3, 2015 at 15:32 Comment(0)
C
1

Its better to use an AsyncTask to get something from internet in the background. And there is no need to pass a static context though. And activity

new YourAsyncTask(context).execute();

Call AsyncTask like above

private class YourAsynTask extends AsyncTask<String,Void,String>
{
 private Context context;
 private ProgressDialog progressDialog;

 //pass context in constructor
  public YourAsynTask(Context context)
  {
     this.context = context;
  }

  //show progress in onPre 
  @Override
  protected void onPreExecute()
  {
    //show Progress code here.
    progressDialog = ProgressDialog.show(context, "", "Loading. Please wait...", true);
  }

  //dismiss Progress dialog in onPost
  @Override 
  protected void OnPostExecute(String response)
  {
    if(progressDialog!=null)
     progressDialog.dismiss();
     progressDialog = null;
  }
}
Calcic answered 2/5, 2016 at 6:14 Comment(0)
W
1

Just call the cancel() method when another activity comes into the foreground.

@Override
protected void onStop() {
   super.onStop();
   this.mProgress.cancel();
}
Windywindzer answered 5/11, 2019 at 17:18 Comment(0)
T
1

I was gettin this exception

@Override
    protected void onResume() {
        super.onResume();//at this line
        showProgressDialog();
    }

This fix worked for me:

  @Override
        protected void onResume() {
            showProgressDialog();
            super.onResume();
        }
Tankersley answered 28/12, 2019 at 11:24 Comment(0)
J
-1

Try calling progressDialog.dismiss() before the activity gets killed. I got mine fixed like this.

Jamal answered 28/7, 2017 at 17:13 Comment(1)
Better put a check if activity is alive by activity != null && !activity.isFinishing() before showing the progress dialogExine

© 2022 - 2024 — McMap. All rights reserved.