web-dev-qa-db-fra.com

android Voir non attaché au gestionnaire de fenêtres

J'ai quelques-unes des exceptions suivantes:

Java.lang.IllegalArgumentException: View not attached to window manager
at Android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.Java:355)
at Android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.Java:191)
at Android.view.Window$LocalWindowManager.updateViewLayout(Window.Java:428)
at Android.app.Dialog.onWindowAttributesChanged(Dialog.Java:596)
at Android.view.Window.setDefaultWindowFormat(Window.Java:1013)
at com.Android.internal.policy.impl.PhoneWindow.access$700(PhoneWindow.Java:86)
at com.Android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.Java:1951)
at com.Android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.Java:1889)
at Android.view.ViewRoot.performTraversals(ViewRoot.Java:727)
at Android.view.ViewRoot.handleMessage(ViewRoot.Java:1633)
at Android.os.Handler.dispatchMessage(Handler.Java:99)
at Android.os.Looper.loop(Looper.Java:123)
at Android.app.ActivityThread.main(ActivityThread.Java:4338)
at Java.lang.reflect.Method.invokeNative(Native Method)
at Java.lang.reflect.Method.invoke(Method.Java:521)
at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:860)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:618)
at dalvik.system.NativeStart.main(Native Method)

Je l'ai googlé et je vois qu'il y a quelque chose à voir avec les popups et le fait de tourner l'écran, mais il n'y a aucune référence à mon code.

Les questions sont:

  1. existe-t-il un moyen de savoir au moment précis où cette question se produit ?__.
  2. À part tourner l'écran, y a-t-il un autre événement ou une autre action qui déclenche cette erreur?
  3. comment puis-je empêcher cela?
106
Daniel Benedykt

J'ai eu ce problème où sur un changement d'orientation de l'écran, l'activité s'est terminée avant la tâche Async avec la boîte de dialogue de progression terminée. J'ai semblé résoudre ce problème en définissant la boîte de dialogue sur null onPause(), puis en la vérifiant dans AsyncTask avant de la fermer. 

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

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

... dans ma tâche Async:

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
            true);
}

protected void onPostExecute(Object result) {
   if ((mDialog != null) && mDialog.isShowing()) { 
        mDialog.dismiss();
   }
}
157
johnnyblizzard

Après un combat avec ce problème, je me retrouve finalement avec cette solution de contournement:

/**
 * Dismiss {@link ProgressDialog} with check for nullability and SDK version
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissProgressDialog(ProgressDialog dialog) {
    if (dialog != null && dialog.isShowing()) {

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();

            // if the Context used here was an activity AND it hasn't been finished or destroyed
            // then dismiss it
            if (context instanceof Activity) {

                // Api >=17
                if (!((Activity) context).isFinishing() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isDestroyed()) {
                            dismissWithExceptionHandling(dialog);
                        }
                    } else { 
                        // Api < 17. Unfortunately cannot check for isDestroyed()
                        dismissWithExceptionHandling(dialog);
                    }
                }
            } else
                // if the Context used wasn't an Activity, then dismiss it too
                dismissWithExceptionHandling(dialog);
        }
        dialog = null;
    }
}

/**
 * Dismiss {@link ProgressDialog} with try catch
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissWithExceptionHandling(ProgressDialog dialog) {
    try {
        dialog.dismiss();
    } catch (final IllegalArgumentException e) {
        // Do nothing.
    } catch (final Exception e) {
        // Do nothing.
    } finally {
        dialog = null;
    }
}

Parfois, une bonne gestion des exceptions fonctionne bien s’il n’ya pas de meilleure solution à ce problème.

8
blueware

Si vous avez un objet Activity à traîner, vous pouvez utiliser la méthode isDestroyed():

Activity activity;

// ...

if (!activity.isDestroyed()) {
    // ...
}

C'est bien si vous avez une sous-classe AsyncTask non anonyme que vous utilisez à différents endroits.

3
shawkinaw

J'ai ajouté ce qui suit au manifeste pour cette activité

Android:configChanges="keyboardHidden|orientation|screenLayout"
2
Rickey

J'utilise une classe statique personnalisée qui montre et cache un dialogue . Cette classe est utilisée par d'autres activités, et pas seulement par une activité . Maintenant, le problème que vous avez décrit m'est aussi apparu et j'ai passé la nuit. pour trouver une solution ..

Enfin je vous présente la solution!

si vous voulez afficher ou fermer une boîte de dialogue et que vous ne savez pas quelle activité a initié la boîte de dialogue afin de la toucher, le code suivant est pour vous.

 static class CustomDialog{

     public static void initDialog(){
         ...
         //init code
         ...
     }

      public static void showDialog(){
         ...
         //init code for show dialog
         ...
     }

     /****This is your Dismiss dialog code :D*******/
     public static void dismissProgressDialog(Context context) {                
            //Can't touch other View of other Activiy..
            //http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-Android
            if ( (progressdialog != null) && progressdialog.isShowing()) {

                //is it the same context from the caller ?
                Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());

                Class caller_context= context.getClass();
                Activity call_Act = (Activity)context;
                Class progress_context= progressdialog.getContext().getClass();

                Boolean is_act= ( (progressdialog.getContext()) instanceof  Activity )?true:false;
                Boolean is_ctw= ( (progressdialog.getContext()) instanceof  ContextThemeWrapper )?true:false;

                if (is_ctw) {
                    ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
                    Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() ==  call_Act )?true:false;

                    if (is_same_acivity_with_Caller){
                        progressdialog.dismiss();
                        progressdialog = null;
                    }
                    else {
                        Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
                        progressdialog = null;
                    }
                }


            }
        } 

 }
2
aimiliano

La solution ci-dessus n'a pas fonctionné pour moi. Donc, ce que j’ai fait est de prendre ProgressDialog comme globalement, puis d’ajouter ceci à mon activité

@Override
    protected void onDestroy() {
        if (progressDialog != null && progressDialog.isShowing())
            progressDialog.dismiss();
        super.onDestroy();
    }

de sorte que dans le cas où l'activité est détruite, ProgressDialog sera également détruit.

0
KishanSolanki124

Une autre option consiste à ne pas démarrer la tâche asynchrone tant que la boîte de dialogue n'est pas attachée à la fenêtre en remplaçant onAttachedToWindow () dans la boîte de dialogue, de sorte qu'elle soit toujours désactivée.

0
Nick Palmer

selon le code de windowManager (link here ), cela se produit lorsque la vue que vous essayez de mettre à jour (qui appartient probablement à une boîte de dialogue, mais pas nécessaire) n'est plus attachée à la racine réelle des fenêtres.

comme d'autres l'ont suggéré, vous devez vérifier le statut de l'activité avant d'effectuer des opérations spéciales sur vos dialogues. 

voici le code relavant, qui est la cause du problème (copié à partir du code source Android): 

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams
            = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);

    synchronized (this) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots[index];
        mParams[index] = wparams;
        root.setLayoutParams(wparams, false);
    }
}

private int findViewLocked(View view, boolean required) {
        synchronized (this) {
            final int count = mViews != null ? mViews.length : 0;
            for (int i=0; i<count; i++) {
                if (mViews[i] == view) {
                    return i;
                }
            }
            if (required) {
                throw new IllegalArgumentException(
                        "View not attached to window manager");
            }
            return -1;
        }
    }
0
android developer

Ou simplement vous pouvez ajouter 

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}

ce qui rendra la ProgressDialog non annulable 

0
Sarith Vasu

Mon problème a été résolu en appliquant la rotation de l'écran sur mon application Android qui me causait un problème fonctionne maintenant parfaitement

0
Roger

Pour la question 1):

Étant donné que le message d'erreur ne semble pas indiquer quelle ligne de votre code est à l'origine du problème, vous pouvez la rechercher à l'aide de points d'arrêt. Les points d'arrêt mettent en pause l'exécution du programme lorsque ce dernier obtient des lignes de code spécifiques. En ajoutant des points d'arrêt aux emplacements critiques, vous pouvez déterminer la ligne de code à l'origine du blocage. Par exemple, si votre programme se bloque sur une ligne setContentView (), vous pouvez y placer un point d'arrêt. Lorsque le programme est exécuté, il se met en pause avant d’exécuter cette ligne. Si la reprise provoque le blocage du programme avant d'atteindre le prochain point d'arrêt, vous savez alors que la ligne qui l'a tué se situe entre les deux points d'arrêt.

L'ajout de points d'arrêt est facile si vous utilisez Eclipse. Faites un clic droit dans la marge située à gauche de votre code et sélectionnez "Basculer le point d'arrêt". Vous devez ensuite exécuter votre application en mode débogage, le bouton qui ressemble à un insecte vert à côté du bouton d’exécution normal. Lorsque le programme atteint un point d'arrêt, Eclipse passe en perspective de débogage et affiche la ligne à laquelle il est en attente. Pour relancer le programme, recherchez le bouton «Reprendre», qui ressemble à un «Lecture» normal, mais avec une barre verticale à la gauche du triangle.

Vous pouvez également remplir votre application avec Log.d ("Mon application", "Certaines informations vous indiquant où se trouve la ligne de journal"), qui publie ensuite des messages dans la fenêtre LogCat d'Eclipse. Si vous ne trouvez pas cette fenêtre, ouvrez-la avec Fenêtre -> Afficher la vue -> Autre ... -> Android -> LogCat.

J'espère que cela pourra aider!

0
Steve Haley