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);
}
});
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)
Utilisation:
progressDialog.dismiss();
en fin de travail
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();
}
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);
}
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.
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é.
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;
}
}
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.