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 ]

2 голосов
/ 29 июля 2010

alex,

Я могу ошибаться, но я подозреваю, что у нескольких телефонов «в дикой природе» есть ошибка, которая заставляет их переключать ориентацию в приложениях, помеченных как статически ориентированные. Это происходит довольно часто на моем личном телефоне, и на многих тестовых телефонах, которые использует наша группа (включая droid, n1, g1, hero). Обычно приложение, помеченное как статически ориентированное (возможно, вертикально), выкладывается на секунду или две, используя горизонтальную ориентацию, а затем немедленно переключается обратно. Конечным результатом является то, что даже если вы не хотите, чтобы ваше приложение меняло ориентацию, вы должны быть готовы к этому. Я не знаю, при каких условиях это поведение может быть воспроизведено, я не знаю, относится ли оно к определенной версии Android. Все, что я знаю, это то, что я видел это много раз: (

Я бы рекомендовал использовать предоставленное решение в ссылке, которую вы разместили , которая предлагает переопределить метод Activity onCreateDialog и позволить ОС Android управлять жизненным циклом ваших диалогов. Мне кажется, что даже если вы не хотите, чтобы ваша деятельность меняла ориентацию, она где-то меняет ориентацию. Вы можете попытаться отследить метод, который всегда будет препятствовать переключению ориентации, но я пытаюсь сказать вам, что лично я не верю, что есть надежный способ, который работает на всех современных телефонах Android на рынке.

2 голосов
/ 13 мая 2010

Я думаю, что ваш код правильный, в отличие от предложенного другого ответа. onPostExecute будет работать в потоке пользовательского интерфейса. В этом весь смысл AsyncTask - вам не нужно беспокоиться о вызове runOnUiThread или о обработчиках. Кроме того, согласно документации, dismiss () может быть безопасно вызван из любого потока (не уверен, что они сделали это исключением).

Возможно, это проблема синхронизации, когда dialog.dismiss () вызывается после того, как действие больше не отображается?

Как насчет тестирования, что произойдет, если вы закомментируете setOnCancelListener, а затем выйдете из действия во время выполнения фоновой задачи? Затем ваш onPostExecute попытается закрыть уже закрытое диалоговое окно. Если приложение дает сбой, вы можете просто проверить, открыто ли диалоговое окно, прежде чем закрыть его.

У меня точно такая же проблема, поэтому я собираюсь попробовать это в коде.

1 голос
/ 02 сентября 2014
@Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            if (progressDialog != null && progressDialog.isShowing()) {
                Log.i(TAG, "onPostexucte");
                progressDialog.dismiss();
}
}
1 голос
/ 21 мая 2013

У меня была такая же проблема при использовании кнопки для синхронизации списка с сервера: 1) нажимаю на кнопку 2) При загрузке списка с сервера появляется диалоговое окно прогресса. 3) Я поворачиваю устройство в другую ориентацию 4) java.lang.IllegalArgumentException: представление не присоединено к оконному менеджеру в postExecute () AsyncTask во время progress.dismiss ().

Когда я попробовал это исправление, я понял, что даже если проблема не возникает, в моем списке отображаются не все элементы.

Я решил, что AsyncTask должен завершить (и закрыть диалоговое окно) до уничтожения beign действия, поэтому я сделал объект asynctask атрибутом и переопределил метод onDestroy ().

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

private AsyncTask<Boolean, Void, Boolean> atask;

@Override
protected void onDestroy() {
    if (atask!=null)
        try {
            atask.get();
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
        }
    super.onDestroy();
}
0 голосов
/ 27 июля 2017

Может ниже код работает для вас, он прекрасно работает для меня:

private void viewDialog() {
    try {
        Intent vpnIntent = new Intent(context, UtilityVpnService.class);
        context.startService(vpnIntent);
        final View Dialogview = View.inflate(getBaseContext(), R.layout.alert_open_internet, null);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
        windowManager.addView(Dialogview, params);

        Button btn_cancel = (Button) Dialogview.findViewById(R.id.btn_canceldialog_internetblocked);
        Button btn_okay = (Button) Dialogview.findViewById(R.id.btn_openmainactivity);
        RelativeLayout relativeLayout = (RelativeLayout) Dialogview.findViewById(R.id.rellayout_dialog);

            btn_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (Dialogview != null) {
//                                ( (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                    windowManager.removeView(Dialogview);
                                }
                            } catch (final IllegalArgumentException e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } catch (final Exception e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } finally {
                                try {
                                    if (windowManager != null && Dialogview != null) {
//                                    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                        windowManager.removeView(Dialogview);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            //    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
//                        windowManager.removeView(Dialogview);


                        }
                    });
                }
            });
            btn_okay.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            //        ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                            try {
                                if (windowManager != null && Dialogview != null)
                                    windowManager.removeView(Dialogview);
                                Intent intent = new Intent(getBaseContext(), SplashActivity.class);
                                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);


                                context.startActivity(intent);
                            } catch (Exception e) {
                                windowManager.removeView(Dialogview);
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        } catch (Exception e) {
            //` windowManager.removeView(Dialogview);
            e.printStackTrace();
        }
    }

Не определяйте свое представление глобально, если вы вызываете его из фоновой службы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...