java.lang.IllegalArgumentException: представление не привязано к оконному менеджеру - PullRequest
145 голосов
/ 30 апреля 2010

У меня есть действие, которое запускает AsyncTask и показывает диалоговое окно прогресса на время операции. Деятельность объявлена ​​НЕ воссозданной вращением или скольжением клавиатуры.

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

Как только задача выполнена, я закрываю диалог, но на некоторых телефонах (framework: 1.5, 1.6) выдается такая ошибка:

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)

Мой код:

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();

Из того, что я прочитал (http://bend -ing.blogspot.com / 2008/11 / правильно-обрабатывать-прогресс-dialog-in.html ) и видел в источниках Android, выглядит единственная возможная ситуация, чтобы получить это исключение, это когда деятельность была уничтожена. Но, как я уже говорил, я запрещаю активный отдых для основных событий.

Так что любые предложения очень ценятся.

Ответы [ 15 ]

224 голосов
/ 24 февраля 2011

Я тоже получаю эту ошибку иногда , когда закрываю диалог и завершаю деятельность из метода onPostExecute Я предполагаю, что иногда действие завершается до успешного закрытия диалога.

Простое, но эффективное решение, которое работает для меня

@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;
    }  
}
11 голосов
/ 21 января 2011

У меня может быть обходной путь.

У меня возникла та же проблема, когда я загружаю множество элементов (через файловую систему) в ListView через AsyncTask. Если бы onPreExecute() запустил ProgressDialog, а затем onPostExecute() и onCancelled() (вызванные, когда задача была явно отменена с помощью AsyncTask.cancel()), закрыв ее с помощью .cancel().

Получила ту же ошибку "java.lang.IllegalArgumentException: Просмотр не присоединен к оконному менеджеру", когда я убивал диалог в методе onCancelled() AsyncTask (я видел, как это было сделано в отличном Приложение полки ).

Обходной путь должен был создать в AsyncTask открытое поле, содержащее ProgressDialog:

public ProgressDialog mDialog;

Затем, в onDestroy(), когда я отменяю свой AsyncTask, я также могу убить связанный диалог через:

AsyncTask.mDialog.cancel();

Вызов AsyncTask.cancel() ДЕЛАЕТ триггер onCancelled() в AsyncTask, но по какой-то причине к тому времени, когда этот метод вызывается, представление уже уничтожено, и, таким образом, отмена диалога завершается неудачей.

10 голосов
/ 07 января 2016

Вот мое «пуленепробиваемое» решение, которое представляет собой сборник всех хороших ответов, которые я нашел по этой теме (спасибо @Damjan и @Kachi).Здесь исключение проглатывается, только если все остальные способы обнаружения не увенчались успехом.В моем случае мне нужно закрыть диалоговое окно автоматически, и это единственный способ защитить приложение от сбоев.Я надеюсь, что это поможет вам!Пожалуйста, голосуйте и оставляйте комментарии, если у вас есть замечания или лучшее решение.Спасибо!

public void dismissWithCheck(Dialog dialog) {
        if (dialog != null) {
            if (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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) {
                            dismissWithTryCatch(dialog);
                        }
                    } else {

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

    public void dismissWithTryCatch(Dialog dialog) {
        try {
            dialog.dismiss();
        } catch (final IllegalArgumentException e) {
            // Do nothing.
        } catch (final Exception e) {
            // Do nothing.
        } finally {
            dialog = null;
        }
    }
8 голосов
/ 09 ноября 2014

Вот правильное решение этой проблемы:

public void hideProgress() {
    if(mProgressDialog != null) {
        if(mProgressDialog.isShowing()) { //check if dialog is showing.

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper)mProgressDialog.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) { 
                if(!((Activity)context).isFinishing() && !((Activity)context).isDestroyed()) 
                    mProgressDialog.dismiss();
            } else //if the Context used wasnt an Activity, then dismiss it too
                mProgressDialog.dismiss();
        }
        mProgressDialog = null;
    }
}

Вместо того, чтобы слепо перехватывать все исключения, это решение решает корень проблемы: пытается закрыть диалоговое окно, когда действие, использованное для инициализации диалога, уже завершено. Работаю на моем Nexus 4 под управлением KitKat, но должен работать на всех версиях Android.

5 голосов
/ 11 марта 2013

Я согласен с мнением Дамжана.
если вы используете много диалогов, следует закрыть все диалоги в onDestroy () или onStop ().
тогда вы сможете уменьшить частоту возникновения исключения «java.lang.IllegalArgumentException: представление не привязано к оконному менеджеру».

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



но немного превосходит ...
чтобы сделать это более понятным, вы запрещаете показывать любой диалог после вызова onDestroy.
я не использую, как показано ниже. но это понятно.

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();
}


удачи!

4 голосов
/ 26 сентября 2012

Используйте это.

if(_dialog!=null && _dialog.isShowing())
_dialog.dismiss();
3 голосов
/ 16 июля 2014

У меня была такая же проблема, вы можете решить ее:

@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;
    }  
}
2 голосов
/ 21 сентября 2015

Прежде всего, выполняйте обработку ошибок там, где вы пытаетесь закрыть диалоговое окно.

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

Если это не помогло, тогда отклоните его в методе действия onStop ().

 @Override
    protected void onStop() {
        super.onStop();
        if ((progressDialog != null) && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }
2 голосов
/ 28 сентября 2014

Объявление объявлено НЕ воссозданным с помощью вращения или скольжения клавиатуры.

Просто получил ту же проблему. Исправлено для уровня API 13 или выше.
Из документов Android:

Примечание. Если ваше приложение предназначено для уровня API 13 или выше (как заявлено атрибутами minSdkVersion и targetSdkVersion), вам также следует объявить конфигурацию «screenSize», поскольку она также изменяется, когда устройство переключается между книжной и альбомной ориентациями.

Итак, я изменил свой манифест на это:

<activity
        android:name="MyActivity"
        android:configChanges="orientation|screenSize"
        android:label="MyActivityName" >
</activity>

А теперь все работает нормально. Активность не воссоздается, когда я поворачиваю телефон, диалоговое окно прогресса и вид остаются прежними. Для меня нет ошибки.

2 голосов
/ 24 сентября 2013

Что мне больше всего помогло, так это проверить, не заканчивается ли действие.

if (!mActivity.isFinishing()) {
    dialog.dismiss();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...