Активность просочилась окно, которое было первоначально добавлено


1163

Что это за ошибка и почему она происходит?

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

Ответы:


1562

Вы пытаетесь показать диалог после выхода из действия.

[РЕДАКТИРОВАТЬ]

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

Ответ 1 :

Вы пытаетесь показать диалог после выхода из действия.

Ответ 2

Эта ошибка может быть немного вводящей в заблуждение при некоторых обстоятельствах (хотя ответ все еще полностью точен) - то есть в моем случае необработанное исключение было брошено в AsyncTask, что вызвало завершение Activity, затем открытое диалоги выполнения вызвало это Exception .. так «реальное» исключение было немного раньше в журнале

Ответ 3

Вызовите dismiss () для экземпляра Dialog, который вы создали до выхода из Activity, например, в onPause () или onDestroy ()


2
@Override public void onStop () {if (dialog! = Null) {dialog.dismiss (); диалог = ноль; }}
Md.Tarikul Islam

14
Даже после 8 лет это все еще актуально! Я получил исключение, потому что активность была закрыта, когда он пытался отобразить мой AlertDialog (так ответ 2). В конце концов я обнаружил, что приложение добавляет «нулевой» объект на сцену (не должно было случиться, но это произошло), но это не дало дополнительного исключения, и все это было замаскировано «утечка» окно "исключение вместо.
Неф.

Можно ли отсканировать все открытые диалоги и закрыть их все в onStop ()? Я генерирую диалоги в ListView при нажатии на элементы. Я не уверен, как получить их ссылку на OnStop.
Myoch

1
Ответ 3 - лучшее решение. работал очень для меня. Спасибо, Казе, Алекс!
amit bansode

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

406

Решение состоит в том, чтобы позвонить 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()на AlertDialog.


4
Именно то, что случилось со мной. Кроме того, вызов hide () и затем установка диалога в null также не является допустимой альтернативой.
Лукас Тулио

Я бы действительно знал проблему, стоящую за этим. Но вызов dismiss () помог мне!
Кароли

59

Вы можете получить это исключение простой / тупой ошибкой, например, случайно вызвав finish()после отображения оператора AlertDialog, если вы пропустите оператор прерывания вызова в операторе switch ...

   @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[]ошибка означает, что диалоговое окно было открыто при закрытии приложения. Но почему?

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

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

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

Одна ошибка вызывает другую, которая вызывает другую, как DOMINOS!


2
Не могу поверить, что у этого есть только одно возражение ... или мы просто очень плохи в программировании, хахаха Мне также понравилась твоя аналогия с домино
user2161301

Решите первую ошибку, и вторая ошибка не произойдет . Эта аналогия помогла мне.
Итабдулла

Это не совсем верно, такие случаи, как ротация телефона, также могут вызывать ротацию «активности».
Sreekanth Karumanaghat

36

Эта проблема возникает при попытке показать диалоговое окно после выхода из действия.

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

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

По сути, из какого класса вы начали progressDialog, переопределите метод onDestroy и сделайте так. Это решило проблему "активность утекла окно".


onDestroy не гарантированно будет вызван. Лучше поместить этот код в onPause или onStop
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 () перед вызовом finish (). Сменив его на mDialog.dismiss (), добились цели.
Май

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блока, и это решило проблему.

Я думал, что как только вы позвоните «закончить», это остановит все и сразу же закончится, но это не так. Похоже, что он доходит до конца блока кода, в котором он завершается.

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

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

Это не ответ на вопрос, но он имеет отношение к теме.

Если действие определило атрибут в манифесте

 android:noHistory="true"

затем после выполнения onPause () контекст действия теряется. Таким образом, все представления, использующие этот контекст, могут выдавать эту ошибку.


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

1
это работает для меня отлично: android: noHistory = "true"
Шохель Рана

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

У меня была проблема, когда я закончил Activity, когда 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/issues/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 catch и dismiss при возникновении исключения

Просто используйте ниже код

 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-вызов, и когда я поворачиваю экран, активность отключается, но перед Dialog.show (), похоже, isShown == true, а затем Dialog падает, несмотря на эту проверку
Михал Зиобро

1

Просто убедитесь, что ваша деятельность не закрывается неожиданно из-за некоторых исключений, возникающих где-то в вашем коде. Обычно это происходит в асинхронной задаче, когда действие сталкивается с принудительным закрытием в методе 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.