Діяльність просочилася вікном, яке було додано спочатку


1160

Що це за помилка і чому вона трапляється?

05-17 18:24:57.069: ERROR/WindowManager(18850): Activity com.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850): android.view.WindowLeaked: Activity ccom.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.view.ViewRoot.<init>(ViewRoot.java:231)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.Dialog.show(Dialog.java:239)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at com.mypkg.myP$PreparePairingLinkageData.onPreExecute(viewP.java:183)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.os.AsyncTask.execute(AsyncTask.java:391)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at com.mypkg.myP.onCreate(viewP.java:94)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.ActivityThread.access$2200(ActivityThread.java:126)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.os.Looper.loop(Looper.java:123)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at android.app.ActivityThread.main(ActivityThread.java:4595)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at java.lang.reflect.Method.invokeNative(Native Method)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at java.lang.reflect.Method.invoke(Method.java:521)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
05-17 18:24:57.069: ERROR/WindowManager(18850):     at dalvik.system.NativeStart.main(Native Method)

6
Інша класика - це коли орієнтація змінюється: stackoverflow.com/questions/1111980/…
rds

Відповіді:


1559

Ви намагаєтесь відкрити діалоговий вікно після того, як ви вийшли з дії.

[EDIT]

Це питання є одним із найпопулярніших пошуків Google для розробника Android, тому додайте кілька важливих моментів із коментарів, які можуть бути кориснішими для майбутнього слідчого, не заглиблюючись у глибоку розмову про коментарі.

Відповідь 1 :

Ви намагаєтесь відкрити діалоговий вікно після того, як ви вийшли з дії.

Відповідь 2

Ця помилка може бути дещо оманливою в деяких обставинах (хоча відповідь все ще є абсолютно точною) - тобто в моєму випадку некерований виняток був кинутий у AsyncTask, що призвело до відключення діяльності, тоді відкритий діалог прогресу спричинив цей виняток. "справжній" виняток був трохи раніше в журналі

Відповідь 3

Виклик відхилення () в екземплярі діалогу, який ви створили перед виходом із своєї діяльності, наприклад, в onPause () або onDestroy ()


2
@Override public void onStop () {if (dialog! = Null) {dialog.dismiss (); діалог = null; }}
Md.Tarikul Іслам

14
Навіть через 8 років це все ще актуально! Я отримав виняток, оскільки активність була закрита, коли вона намагалася відобразити мій AlertDialog (так відповідь 2). Зрештою я з’ясував, що додаток додає об’єкт "null" на сцену (не повинно було статися, але це сталося), але це не дало зайвого винятку для цього, і все це замаскувалося "просоченим" виняток "замість цього.
Неф

Чи можливо сканувати всі відкриті діалогові вікна та закрити їх у onStop ()? Я генерую діалоги в ListView при натисканні на елементи. Я не впевнений, як отримати їх посилання з onStop.
Міох

1
Відповідь 3 - найкраще рішення. багато працював для мене. Дякую казе, Алекс !!
amit bansode

додаткова підказка, якщо ви відображаєте діалог у циклі, переконайтеся, що цикл закінчується після завершення діяльності
Thecarisma

405

Рішення полягає в тому, щоб зателефонувати dismiss()на Dialogстворене вами, viewP.java:183перш ніж вийти з нього Activity, наприклад, в onPause(). Перед тим, як залишити анкету, слід закрити всі Windows & Dialogs Activity.


3
Отже, коли користувач повертає телефон, усі діалоги слід відхилити ?? Це не звучить правильно.
LarsH

@LarsH, як бачите, моя відповідь була написана більше 7 років тому, і це, безумовно, було правдою на той час. Я більше не працюю з Android, але виходячи з того, що я бачу в документації , це все-таки може бути, але Android пройшов довгий шлях (представив фрагменти просто для того, щоб назвати його), так що, напевно, зараз простіше.
монарм

108

Якщо ви використовуєте AsyncTask, ймовірно, що повідомлення журналу може бути оманливим. Якщо ви заглянете у свій журнал, ви можете виявити ще одну помилку, ймовірно, одну в своєму doInBackground()методі свого AsyncTask, що змушує ваш струм Activityпідірватись, і, таким чином, як тільки AsyncTaskповернеться .. ну, ви знаєте решту. Деякі інші користувачі вже пояснили, що тут :-)


22
Іноді в такому випадку я не в змозі побачити реальний виняток. Щоб знайти справжній виняток, просто прокоментуйте progressDialog.show () та запустіть додаток знову .. тепер ви це бачите.
Застряг

Привіт, люди! Як згадував вище @Stuck, я також не в змозі побачити реальний виняток. Що я зробив? Я розшукав його , використовуючи ламати окуляри , і я виявив , що я використовував посилання на клас Application всередині методу doInBackgroundв AsyncTaskкласі , але без оголосимо його в AndroidManifestфайл , використовуючи властивість android:nameяк це: android:name="my.package.MyApplicationClass". Доброю практикою при AsyncTaskйого використанні є завжди пам’ятати про те, щоб подати своє попередження всередині методу onPreExecuteта відхилити його onPostExecute.
GFPF

66

Цю помилку я спровокував помилково зателефонувавши hide()замість dismiss()an AlertDialog.


4
Саме так сталося зі мною. Крім того, виклик hidre () та встановлення діалогового вікна на нуль також не є коректною альтернативою.
Лукас Туліо

Я б справді знав питання, що стоїть за цим. Але зателефонувавши до звільнення () мені допомогли!
Каролі

59

Ви можете отримати цей виняток просто простою / німою помилкою, наприклад (випадково) зателефонувавши finish()після відображення AlertDialog, якщо ви пропустите заяву про перерву у виписці з комутацією ...

   @Override
   public void onClick(View v) {
    switch (v.getId()) {
        case R.id.new_button:
            openMyAlertDialog();
            break; <-- If you forget this the finish() method below 
                       will be called while the dialog is showing!
        case R.id.exit_button:
            finish();
            break;
        }
    }

finish()Метод буде закрити Activity, але AlertDialogдо сих пір відображення!

Тож, коли ви пильно дивитесь на код, шукаєте погані проблеми з ниткою або складне кодування тощо, не втрачайте уваги на ліс для дерев. Іноді це може бути просто щось таке просте і німе, як відсутність заяви про перерву. :)


Більш-менш точно моє питання. Викликане завершення в onError після створення діалогового вікна, а не onClick для кнопки відхилення.
jbass

46

Відповіді на це запитання були правильними, але трохи незрозуміло, що я насправді розумію, чому. Погравши близько 2 годин, причина цієї помилки (в моєму випадку) мене вдарила:

Ви вже знаєте, читаючи інші відповіді, що X has leaked window DecorView@d9e6131[]помилка has означає, що діалогове вікно було відкрито, коли додаток закрито. Але чому?

Можливо, ваш додаток вийшов з ладу з якоїсь іншої причини, поки діалогове вікно було відкрито

Це призводить до закриття вашої програми через деяку помилку у вашому коді, яка призводить до того, що діалогове вікно залишається відкритим одночасно із закритим додатком через іншу помилку.

Отже, перегляньте своє логічне. Вирішіть першу помилку, а потім друга помилка вирішить самавведіть тут опис зображення

Одна помилка викликає іншу, яка спричиняє іншу, як DOMINOS!


2
Не можу повірити , що це тільки один upvote .. або ми просто дуже погано програмування хахаха я теж любив свою ланцюгову аналогію
user2161301

Вирішіть першу помилку, а друга помилка не виникне . Ця аналогія мені допомогла.
itabdullah

Це не зовсім правильно, такі випадки, як обертання телефону, також можуть спричинити поворот "активності".
Sreekanth Karumanaghat

36

Ця проблема виникає при спробі показати діалоговий вікно після того, як ви вийшли з активності.

Я просто вирішив цю проблему, записавши наступний код:

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

В основному, з якого класу ви розпочали progressDialog, замініть метод onDestroy і зробіть це так. Це вирішило проблему "Діяльність просочилося вікно".


onDestroy не гарантовано називається. Краще ввести цей код у «Пауза» або «на вершині»
Amruta-Pani

19

Нещодавно я стикався з тим же питанням.

Причиною цього питання є те, що діяльність, яку закривають перед відхиленням діалогу. Існують різні причини для того, щоб сказати вище. Вказані в публікаціях вище також є правильними.

Я потрапив у ситуацію, бо в потоці я викликав функцію, яка кидала виняток. Через що вікно було відхилено, а отже, виняток.


16

Відхиліть діалогове вікно, коли діяльність знищиться

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

якщо pDialog недійсний, це призведе до помилки, коли ви запитуєте про стан діалогу "null"
Джонатан Данн,

1
ні, це не буде @JonDunn, тому що Java не обробить другу булеву, якщо перша помилкова
matdev

13

Це може допомогти.

if (! isFinishing()) {

    dialog.show();

    }

2
Серед сотень подібних відповідей немає жодної, яка б показала, як перевірити наявність вікон. Тож ви заощадите мені деякий час, знаходячи спосіб це зробити. Дякую.
колясег

11

У мене було те саме незрозуміле повідомлення про помилку і не знав, чому. З огляду на підказки з попередніх відповідей, я змінив свої дзвінки, не-GUI, на mDialog.finish () на mDialog.dismiss (), і помилки зникли. Це не впливало на поведінку мого віджета, але було неспокійно і цілком могло позначати важливе витоку пам’яті.


Помітив, що я робив mDialog.hide () перед викликом закінчення (). Змінивши його на mDialog.dismiss () зробив свою справу.
Mays

11

Я отримував ці журнали в додатку для відеоплеєра. Ці повідомлення були кинуті під час закриття відеоплеєра. Цікаво, що я часто отримував ці журнали раз у кілька запусків випадковим чином. Також моя заява не передбачає жодної progressdialog. Нарешті, я обійшов цю проблему із реалізацією нижче.

@Override
protected void onPause()
{
    Log.v("MediaVideo", "onPause");
    super.onPause();
    this.mVideoView.pause();
    this.mVideoView.setVisibility(View.GONE);
}

@Override
protected void onDestroy()
{
    Log.v("MediaVideo", "onDestroy");
    super.onDestroy();
}

@Override
protected void onResume()
{
    Log.v("MediaVideo", "onResume");
    super.onResume();
    this.mVideoView.resume();
}

Замініть на OnPauseвиклик mVideoView.pause()та встановити visibilityна GONE. Таким чином я міг вирішити " Activity has leaked window" помилку журналу " ".


Я також зіткнувся з тією ж проблемою. я додав ваші ці рядки коду до мого коду, але він не працював і видає ту ж помилку "android.view.WindowLeaked, що спочатку було додано", а також не відтворює відео та дає "Відео не може бути відтворене"
User42590

10

У мене була та сама проблема, і я знайшов цю сторінку, і, хоча моя ситуація була іншою, я зателефонував finishіз ifблоку, перш ніж він визначив поле сповіщення.

Отже, просто зателефонувати dismissне вийшло (як це ще не було), але прочитавши відповідь Алекса Волового та зрозумівши, що це викликає попередження. Я спробував додати заяву про повернення відразу після фінішу всередині цього ifблоку, і це вирішило проблему.

Я думав, що одного разу ви подзвонили закінчити, це все зупинило і закінчилося прямо там, але це не так. Здається, йде до кінця блоку коду, який він тоді закінчує.

Отже, якщо ви хочете реалізувати ситуацію, коли іноді це закінчиться перед тим, як робити якийсь код, вам доведеться поставити заяву про повернення відразу після фінішу, або вона продовжуватиметься і діятиме так, як фініш викликали в кінці блок коду не там, де ви його назвали. Ось чому я отримував усі ці дивні помилки.

private picked(File aDirectory){
     if(aDirectory.length()==0){
        setResult(RESULT_CANCELED, new Intent()); 
        finish(); 
        return;
    }
     AlertDialog.Builder alert= new AlertDialog.Builder(this); // Start dialog builder
     alert
        .setTitle("Question")
        .setMessage("Do you want to open that file?"+aDirectory.getName());
    alert
        .setPositiveButton("OK", okButtonListener)
        .setNegativeButton("Cancel", cancelButtonListener);
    alert.show();
}

Якщо ви не поставите повернення відразу після того, як я зателефонував закінчити, він буде діяти так, як ніби ви його зателефонували після, alert.show();і, отже, він би сказав, що вікно просочилося, закінчившись після того, як ви відкрили діалогове вікно, навіть якщо це це не так, він все ще вважає, що це так.

Я думав, що додам це як тут, як це показує, що команда фінішу діяла інакше, тоді я думала, що це зробило, і я здогадуюсь, що є інші люди, які думають так само, як і я, перш ніж я це відкрив.


7

Це не відповідь на питання, але це стосується теми.

Якщо активність визначила атрибут у Manifest

 android:noHistory="true"

то після виконання onPause () контекст активності втрачається. Отже, усі представлення даних, що використовують цей контекст, можуть призвести до цієї помилки.


Можете чи ви зв'язати що - небудь подібне для progessdialog.show().. і progressdialog.hide()в asynctaskодній і тій же діяльності , а не onPause()від activity?? подивитися на мою проблему ... stackoverflow.com/questions/39332880 / ...
Bhuro

1
це працює для мене чудово: android: noHistory = "справжній"
Shohel Rana

6

Не тільки намагайтеся показувати сповіщення, але і його можна викликати, коли ви закінчите певний екземпляр діяльності та спробуйте запустити нову діяльність / послугу або спробуйте її зупинити.

Приклад:

OldActivity instance;

    oncreate() {
       instance=this;
    }
    instance.finish();
    instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));

6

Зазвичай ця проблема виникає через діалог прогрес: ви можете вирішити це за допомогою будь-якого із наведених нижче методів у вашій діяльності:

 // 1):
          @Override
                protected void onPause() {
                    super.onPause();
                    if ( yourProgressDialog!=null && yourProgressDialog.isShowing() )
                  {
                        yourProgressDialog.cancel();
                    }
                }

       // 2) :
         @Override
            protected void onDestroy() {
                super.onDestroy();
                if ( yourProgressDialog!=null && yourProgressDialog.isShowing()
               {
                    yourProgressDialog.cancel();
                }
            }

5

Виникла проблема, коли я закінчив діяльність, коли ще показали програму ProgressDialog.

Тому спочатку прихойте Діалог, а потім закінчіть діяльність.


5

Спробуйте цей код:

public class Sample extends Activity(){
@Override
 public void onCreate(Bundle instance){

}
 @Override
    public void onStop() {
        super.onStop();
      progressdialog.dismiss(); // try this
    }

}

progressdialog.dismiss();це може створити NullPointerException.
tpk

5

Це може бути, якщо у вас є помилка в роботі doInBackground()функції та цей код.

Спробуйте остаточно додати діалогове вікно. Спочатку перевірити та виправити doInBackground()функцію

protected void onPreExecute() {
     super.onPreExecute();
     pDialog = new ProgressDialog(CreateAccount.this);
     pDialog.setMessage("Creating Product..");
     pDialog.setIndeterminate(false);
     pDialog.setCancelable(true);
     pDialog.show();

 }

 protected String doInBackground(String...args) {
     ERROR CAN BE IS HERE
 }

 protected void onPostExecute(String file_url) {
     // dismiss the dialog once done
     pDialog.dismiss();

5

Це трапилося зі мною , коли я використовую ProgressDialogв AsyncTask. Насправді я використовую hide()метод в onPostExecute. На підставі відповіді @Alex Volovoy мені потрібно використовувати dismiss()з , ProgressDialogщоб видалити його в onPostExecute і його зробили.

progressDialog.hide(); // Don't use it, it gives error

progressDialog.dismiss(); // Use it

Це насправді не повна відповідь. Існує два способи протікання діалогового вікна. 1) Якщо у вас є AsyncTaskі ви показуєте Dialog, тоді відбувається щось, що робить Activityдзвінок onPause()(можливо, якась логіка у вашому AsyncTask, як у слухача, тоді він просочиться. 2) Як було сказано вище, те, Dialogщо було створено за допомогою цього Activity Context, ніколи не буває звільнений і Activityрухається далі.
хитрологія

5

Activity has leaked window that was originally added...Помилка " " виникає, коли ви намагаєтесь показати сповіщення після того, Activityяк ефективно з'явиться finished.

У вас є два варіанти AFAIK:

  1. Перегляньте логін вашого сповіщення: зателефонуйте dismiss()наdialog як фактично завершите свою діяльність.
  2. Помістіть dialogв іншу нитку і запустіть її на цій thread(незалежно від струму activity).

5

ось рішення, коли ви хочете відмовитись від AlertDialog, але не хочете зберігати посилання на нього всередині діяльності.

рішення вимагає, щоб ви мали androidx.lifecycle у вашому проекті залежність від (я вважаю, що на момент коментаря це загальна вимога)

це дозволяє вам делегувати відхилення діалогового вікна зовнішньому об’єкту (спостерігачеві), і вам більше про це не потрібно дбати, оскільки він автоматично скасовується, коли активність вмирає. (ось доказ: https://github.com/googlecodelabs/android-lifecycles/isissue/5 ).

Таким чином, спостерігач зберігає посилання на діалог, а діяльність зберігає посилання на спостерігача. коли трапляється "onPause" - спостерігач відхиляє діалогове вікно, а коли відбувається "onDestroy" - активізація видаляє спостерігача, тому витік не відбувається (ну, принаймні, я більше не бачу помилки в logcat)

// observer
class DialogDismissLifecycleObserver( private var dialog: AlertDialog? ) : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        dialog?.dismiss()
        dialog = null
    }
}
// activity code
private fun showDialog() {
        if( isDestroyed || isFinishing ) return
        val dialog = AlertDialog
            .Builder(this, R.style.DialogTheme)
            // dialog setup skipped
            .create()
        lifecycle.addObserver( DialogDismissLifecycleObserver( dialog ) )
        dialog.show()
}

4

Винятки, що витікають з вікон, мають дві причини:

1) відображення діалогового вікна, коли контекст діяльності не існує, для вирішення цього питання слід показувати діалогове вікно лише ви впевнені, що діяльність існує:

if(getActivity()!= null && !getActivity().isFinishing()){
        Dialog.show();
}

2) не відхиляти діалог належним чином, щоб вирішити використання цього коду:

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

4

Ви повинні зробити Progressdialogоб'єкт у onPreExecuteметоді, AsyncTaskі ви повинні dismissце за onPostExecuteметодом.


4

Найкраще рішення - просто додати діалог у діалоговому вікні спробувати вхопити та відхилити, коли трапляються винятки

Просто використовуйте код нижче

 try {
        dialog.show();
    } catch (Exception e) {
        dialog.dismiss();
    }

3
не буде діалог буде нульовим після виклику закінчено? Я думаю dialog.dismiss(), що помилка також буде
Ашу Кумар

3

У моєму випадку причиною стало те, що я забув включити дозвіл у файл маніфесту Android.

Як я дізнався? Ну, так, як говорить @Bobby у коментарі під прийнятою відповіддю, просто прокрутіть далі до своїх журналів, і ви побачите першу причину чи подію, яка насправді кинула Виняток. Мабуть, повідомлення "Діяльність просочилося вікно, яке було додано спочатку" - це лише виняток, який був результатом будь-якого першого винятку.


3

Спробуйте внизу код, він буде працювати щоразу, коли ви відхилите діалог про хід виконання, і він побачить, чи наявний його примірник чи ні.

try {
        if (null != progressDialog && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

2

Найкраще рішення ставити це перед показом progressbarабоprogressDialog

if (getApplicationContext().getWindow().getDecorView().isShown()) {

  //Show Your Progress Dialog

}

Це не працює для мене. У мене є Dialog.show () після відповіді на дзвінок HTTP, і коли я тим часом повертаю екран, активність від'єднується, але, схоже, це єShown == true перед Dialog.show (), а потім Dialog аваріює, незважаючи на цю перевірку
Michał Ziobro

1

Просто переконайтеся, що ваша діяльність не закривається несподівано через деякі винятки, підняті десь у вашому коді. Як правило, це відбувається в задачі async, коли активність стикається із закриттям сили в методі doinBackground, а потім asynctask повертається до методу onPostexecute.


1

У мене є ще одне рішення для цього, і я хотів би знати, чи здається вам це дійсним: замість того, щоб звільняти в onDestroy, який, здається, є провідним рішенням, я продовжую ProgressDialog ...

public class MyProgressDialog extends ProgressDialog {

  private boolean isDismissed;

  public MyProgressDialog(Context context) {
    super(context);
  }

  @Override
  public void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    dismiss();
  }

  @Override
  public void dismiss() {
    if (isDismissed) {
      return;
    }
    try {
      super.dismiss();
    } catch (IllegalArgumentException e) {
      // ignore
    }
    isDismissed = true;
  }

Це краще, AFAIC, тому що вам не потрібно проводити діалог прогресу як член, просто запустити (показати) та забути

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.