ProgressDialog: как предотвратить утечку окна - PullRequest
46 голосов
/ 07 июля 2011

Я использую ProgressDialog для предотвращения взаимодействия пользователя, пока устройство загружает данные из Интернета.

все работало нормально, пока моему клиенту не удалось выдать эту ошибку:

"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)"

и я понятия не имею, как это исправить.

есть идеи, что вызывает это и как это решить?

Журнал отслеживает ошибку до этой строки:

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

решит ли это проблему, если я изменю ее на следующее:

this.runOnUiThread(new Runnable() {
            public void run() {
                progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);
            }
        });

Ответы [ 9 ]

114 голосов
/ 22 декабря 2011

Использование:

progressDialog.dismiss();

в конце работы

17 голосов
/ 13 июля 2011

Утечка, вероятно, происходит из вашего атрибута PixelRainActivity.staticThis. Если вы сохраняете ссылку на действие, даже после того, как это действие было уничтожено, у вас есть утечка памяти.

Самый простой способ исправить это использовать вместо приложения Context. Измените staticThis = this строку в методе onCreate() на staticThis = this.getApplicationContext(), и она должна работать (и измените тип staticThis на Context, если это не так)

4 голосов
/ 23 февраля 2017

Бывают ситуации, когда вам нужно проверить в onDetach или в onDestroy, отображается ли диалоговое окно прогресса.Вот так:

@Override
public void onDetach() {
    if (mProgressDialog != null && mProgressDialog.isShowing())
        mProgressDialog.dismiss();
    super.onDetach();
}
2 голосов
/ 01 декабря 2011

cygnus имеет хорошую идею использовать showDialog (MY_INT), где MY_INT - это просто некоторое постоянное значение, которое вы выбираете, просто чтобы отличить его от любых других подобных диалогов, которые вы запускаете таким образом.Вы снимаете это так же с помощью dismissDialog (MY_INT).Только не запускайте его из вашего метода onPause.Возможно, вы захотите сделать это вместо метода onResume того действия, которое собирается выполнить пользователь.Затем вы переопределяете метод onCreateDialog этого действия следующим образом:

@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);
}
1 голос
/ 07 июля 2011

Вместо использования ProgressDialog.show(), попробуйте использовать

Activity.showDialog(), который должен автоматически управлять Dialog для вас и предотвращать утечки.

РЕДАКТИРОВАТЬ: Когда вы звоните showDialog(int), это вызовет Activity.onCreateDialog(int), где вы можете создать Dialog вы хотите и вернуть Dialog, который вы хотите отобразить.

0 голосов
/ 28 июля 2017

Попробуйте позвонить progressDialog.dismiss() до того, как действие будет убито.Я починил мой вот так.

0 голосов
/ 02 мая 2016

Лучше использовать AsyncTask, чтобы получить что-то из Интернета в фоновом режиме.И нет необходимости передавать статический контекст, хотя.И активность

new YourAsyncTask(context).execute();

Вызовите AsyncTask, как указано выше

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;
  }
}
0 голосов
/ 03 марта 2015

Если вы используете thread или AsyncTask и загружаете материал из интернета и показывает progress bar, вы должны использовать DialogFragment или отменить прогресс dialog, когда Activity прекратите работу, если вы показываете прогресс в Asynctask отмена кулака Asynctask и переопределение oncancel метода обратного вызова и dismiss диалога прогресса там.

Window leak в Activity или fragment на самом деле происходит из-за того, что вы пытаетесь добавить окно, и, пока оно показывает, оно находится на foreground, но когда вы нажимаете дом, оно останавливается и затем останавливается через onStop (). Таким образом, ваш CustomView остается прикрепленным к окну, которое теперь исчезло. Следовательно, в соответствии с системой ваш customView занимал пространство, которое он не освободил.

0 голосов
/ 08 июля 2011

Я столкнулся с подобной проблемой с диалоговым окном прогресса и фоновой задачей.AsyncTask (http://android -developers.blogspot.de / 2009/05 / painless-threading.html ) позволил мне сделать как намного более чисто, так и без утечки.

...