146 votes

java.lang.IllegalArgumentException: vue non attachée au gestionnaire de fenêtres

J'ai une activité qui commence AsyncTask et montre la boîte de dialogue de progression pour la durée de l'opération. L'activité est déclarée ne PAS être recréé par la rotation du clavier ou de la diapositive.

    <activity android:name=".MyActivity" 
              android:label="@string/app_name"
              android:configChanges="keyboardHidden|orientation"
              >
        <intent-filter>
        </intent-filter>
    </activity>

Une fois la tâche terminée, je dissmiss boîte de dialogue, mais sur certains téléphones (cadre: 1.5, 1.6) cette erreur est renvoyée:

java.lang.IllegalArgumentException: View not attached to window manager
    at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:356)
    at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:201)
    at android.view.Window$LocalWindowManager.removeView(Window.java:400)
    at android.app.Dialog.dismissDialog(Dialog.java:268)
    at android.app.Dialog.access$000(Dialog.java:69)
    at android.app.Dialog$1.run(Dialog.java:103)
    at android.app.Dialog.dismiss(Dialog.java:252)
    at xxx.onPostExecute(xxx$1.java:xxx)

Mon code est:

final Dialog dialog = new AlertDialog.Builder(context)
    .setTitle("Processing...")
    .setCancelable(true)
    .create();

final AsyncTask<MyParams, Object, MyResult> task = new AsyncTask<MyParams, Object, MyResult>() {

    @Override
    protected MyResult doInBackground(MyParams... params) {
        // Long operation goes here
    }

    @Override
    protected void onPostExecute(MyResult result) {
        dialog.dismiss();
        onCompletion(result);
    }
};

task.execute(...);

dialog.setOnCancelListener(new OnCancelListener() {
    @Override
    public void onCancel(DialogInterface arg0) {
        task.cancel(false);
    }
});

dialog.show();

De ce que j'ai lu (http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html) et vu dans Android sources, il semble que la seule situation possible pour obtenir que l'exception est lorsque l'activité a été détruit. Mais comme je l'ai mentionné, je défends l'activité de loisirs pour les événements de base.

Donc, toutes les suggestions sont grandement appréciés.

226voto

Damjan Points 1720

J'ai aussi cette erreur parfois quand je rejette le dialogue et termine l'activité de la méthode onPostExecute. Je suppose que parfois l'activité est terminée avant que le dialogue ne réussisse à être rejeté.

Solution simple mais efficace qui fonctionne pour moi

 @Override
protected void onPostExecute(MyResult result) {
    try {
        if ((this.mDialog != null) && this.mDialog.isShowing()) {
            this.mDialog.dismiss();
        }
    } catch (final IllegalArgumentException e) {
        // Handle or log or ignore
    } catch (final Exception e) {
        // Handle or log or ignore
    } finally {
        this.mDialog = null;
    }  
}
 

11voto

Paul Mennega Points 4099

J'ai peut-être une solution de contournement.

A avoir le même problème, où je suis le chargement de beaucoup d'éléments (via le système de fichiers) dans un ListView par le biais d'un AsyncTask. A la onPreExecute() tir d'un ProgressDialog, et puis les deux onPostExecute() et onCancelled() (appelée lorsque la tâche est annulée explicitement via AsyncTask.annuler()) fermeture par .annuler().

Eu le même "de java.lang.IllegalArgumentException: la Vue n'est pas attaché à la fenêtre" gestionnaire de message d'erreur quand j'était en train de tuer la boîte de dialogue dans le onCancelled() la méthode de l'AsyncTask (j'avais vu cette façon de faire dans l'excellente app Étagères).

La solution a été de créer un champ public dans l'AsyncTask qui contient le ProgressDialog:

public ProgressDialog mDialog;

Puis, dans onDestroy() quand j'ai annuler mon AsyncTask, je peux aussi tuer la boîte de dialogue associée par l'intermédiaire de:

AsyncTask.mDialog.cancel();

L'Appel De AsyncTask.annuler() NE déclenchent onCancelled() dans l'AsyncTask, mais pour une raison que par le temps que la méthode est appelée, le point de Vue a déjà été détruites et donc annuler le dialogue est un échec.

5voto

Hogun Points 112

je suis d'accord un avis de 'Damien'.
si vous utilisez plusieurs boîtes de dialogue, devrait fermer toutes les dialogue dans onDestroy() ou onStop().
alors, vous pouvez être en mesure de réduire la fréquence de java.lang.IllegalArgumentException: la Vue n'est pas attaché à la fenêtre gestionnaire' exception se produit.

@Override
protected void onDestroy() {
    Log.d(TAG, "called onDestroy");
    mDialog.dismiss();
    super.onDestroy();
}



mais peu dépasser...
pour rendre cela plus clair, vous empêcher de montrer toute la boîte de dialogue après onDestroy appelé.
je ne l'utilise pas en tant que ci-dessous. mais, c'est clair.

private boolean mIsDestroyed = false;

private void showDialog() {
    closeDialog();

    if (mIsDestroyed) {
        Log.d(TAG, "called onDestroy() already.");
        return;
    }

    mDialog = new AlertDialog(this)
        .setTitle("title")
        .setMessage("This is DialogTest")
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        })
        .create();
    mDialog.show();
}

private void closeDialog() {
    if (mDialog != null) {
        mDialog.dismiss();
    }
}

@Override
protected void onDestroy() {
    Log.d(TAG, "called onDestroy");
    mIsDestroyed = true;
    closeDialog();
    super.onDestroy();
}


bonne chance!

4voto

Pralabh Jain Points 80

Utilisez ceci.

 if(_dialog!=null && _dialog.isShowing())
_dialog.dismiss();
 

2voto

Brandon O'Rourke Points 7509

Je pense que votre code est correct, contrairement à la réponse proposée. onPostExecute sera exécuté sur le thread d'INTERFACE utilisateur. C'est le point de l'ensemble de AsyncTask - vous n'avez pas à vous soucier d'appeler runOnUiThread ou de traiter avec les gestionnaires. En outre, selon les documents, de les rejeter() peut être appelé en toute sécurité à partir de n'importe quel thread (pas sûr qu'ils fait de cette exception).

C'est peut-être un problème de synchronisation lorsque la boîte de dialogue.rejeter() est appelé après que l'activité n'est plus affiché?

Ce qui sur le test de ce qui se passe si vous commentez la setOnCancelListener et puis la sortie de l'activité alors que la tâche d'arrière-plan est en cours d'exécution? Ensuite, votre onPostExecute va essayer de rejeter déjà rejeté boîte de dialogue. Si l'application se bloque, vous pouvez probablement juste de vérifier si le dialogue est ouvert, avant de le rejeter.

J'ai exactement le même problème, donc je vais essayer dans le code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X