web-dev-qa-db-fra.com

ProgressDialog: comment éviter les fuites de fenêtre

J'utilise ProgressDialog pour empêcher l'utilisateur d'interagir pendant que l'appareil télécharge des éléments depuis Internet.

tout fonctionnait bien jusqu'à ce que mon client réussisse à produire ce 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)"

et je n'ai aucune idée de comment résoudre ce problème.

des idées ce qui cause cela et comment le résoudre?

Le journal retrace l'erreur sur cette ligne:

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

cela résoudrait-il le problème si je le remplaçais par ceci:

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

La fuite provient probablement de votre attribut PixelRainActivity.staticThis. Si vous conservez une référence à une activité, même après que cette activité a été détruite, vous avez une fuite de mémoire.

La solution la plus simple consiste à utiliser à la place Context de l'application. Modifiez votre ligne staticThis = this Dans la méthode onCreate() en staticThis = this.getApplicationContext() et cela devrait fonctionner (et changez le type de staticThis en Context si ce n'est pas déjà le cas)

17
Guillaume Brunerie

Utilisation:

progressDialog.dismiss();

en fin de travail

115
Jimmy Collazos

Il existe des situations où vous devez vérifier dans onDetach ou onDestroy si la boîte de dialogue de progression est toujours visible. Ainsi:

@Override
public void onDetach() {
    if (mProgressDialog != null && mProgressDialog.isShowing())
        mProgressDialog.dismiss();
    super.onDetach();
}
4
Diaconu Nicu

cygnus a une bonne idée d'utiliser showDialog (MY_INT), où MY_INT n'est qu'une valeur constante que vous choisissez juste pour la distinguer des autres boîtes de dialogue similaires que vous lancez de cette façon. Vous le supprimez de la même manière avec le renvoiDialog (MY_INT). Ne le lancez pas à partir de votre méthode onPause. Vous pouvez le faire à la place à partir de la méthode onResume de l'activité que l'utilisateur va effectuer. Ensuite, vous remplacez la méthode onCreateDialog de cette activité comme ceci:

@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);
}
2
Melinda Green

Au lieu d'utiliser ProgressDialog.show(), essayez d'utiliser

Activity.showDialog() qui devrait gérer automatiquement le Dialog pour vous et éviter les fuites.

EDIT: Lorsque vous appelez showDialog(int), il déclenchera Activity.onCreateDialog(int) où vous pourrez créer le Dialog que vous voulez et retourner le Dialog que vous voulez afficher.

1
cyngus

Si vous utilisez un thread ou AsyncTask et que vous téléchargez des trucs depuis Internet et que vous montrez progress bar, vous devez utiliser DialogFragment ou annuler la progression dialog lorsque Activity arrêter également si vous affichez la progression dans Asynctask fist annuler Asynctask et remplacer oncancel méthode de rappel et dismiss dialogue de progression à cet endroit.

Window leak dans Activity ou fragment se produit en fait parce que vous essayez d'ajouter une fenêtre et pendant qu'elle apparaît, elle se trouve sur le foreground, mais lorsque vous appuyez sur la touche à la maison, il est mis en pause puis arrêté via le onStop (). Votre CustomView reste donc attaché à la fenêtre qui a maintenant disparu. Par conséquent, selon le système, votre customView a occupé l'espace qu'elle n'a pas libéré.

0
Mahesh

Il vaut mieux utiliser un AsyncTask pour obtenir quelque chose d'Internet en arrière-plan. Et il n'est pas nécessaire de passer un contexte statique cependant. Et activité

new YourAsyncTask(context).execute();

Appelez AsyncTask comme ci-dessus

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
Xar E Ahmer

J'ai rencontré un problème similaire avec une boîte de dialogue de progression et une tâche en arrière-plan. La tâche AsyncTask ( http://Android-developers.blogspot.de/2009/05/pireless-threading.html ) m'a permis de faire les deux de manière beaucoup plus propre et sans la fenêtre qui a fui.

0
Andy Dyer