活动泄漏了最初添加的窗口


1159

这是什么错误,为什么会发生?

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

Answers:


1559

您试图退出活动后显示对话框。

[编辑]

这个问题是Google上针对Android开发人员的热门搜索之一,因此在评论中添加了一些要点,而无需深入地进行评论对话,这可能对将来的研究者更有帮助。

答案1

您试图退出活动后显示对话框。

答案2

在某些情况下(尽管答案仍然完全正确),该错误可能会引起误解-例如,在我的情况下,在AsyncTask中引发了未处理的Exception,这导致Activity关闭,然后打开的进度对话框导致了此Exception。 “真正的”例外在日志中稍早一些

答案3

在退出Activity之前,在您创建的Dialog实例上调用dismiss(),例如在onPause()或onDestroy()中


2
@Override public void onStop(){if(dialog!= null){dialog.dismiss(); dialog = null; }}
塔里库尔伊斯兰教医师

14
即使8年之后,这仍然有意义!我收到异常消息是因为该活动在尝试显示我的AlertDialog时关闭(因此答案2)。最后,我发现该应用程序向场景中添加了一个“空”对象(应该不会发生,但确实发生了),但是并没有给它带来额外的例外,整个过程被“泄漏”所掩盖窗口”例外。
Neph

是否可以扫描所有打开的对话框并在onStop()中将其全部关闭?单击项目时,我在ListView中生成对话框。我不确定如何从onStop检索他们的参考。
Myoch

1
答案3是最好的解决方案。为我工作得很好。谢谢风神,亚历克斯!
阿米(Amit)禁令,

其他提示,如果您正在循环显示对话框,请确保活动结束后退出循环
Thecarisma

404

解决的办法是呼叫dismiss()Dialog您创建中viewP.java:183退出之前Activity,在如onPause()。所有Windows&Dialogs都应在离开之前关闭Activity


3
因此,当用户旋转手机时,应取消所有对话框?听起来不对。
LarsH

如您所见,@ LarsH,我的答案写于7年前,而那时确实是这样。我不再使用Android,但根据我在文档中看到的情况,情况可能仍然如此,但是Android自从推出Fragments以来已经走了很长一段路,所以现在可能更容易了。
molnarm

108

如果使用AsyncTask,则该日志消息可能具有欺骗性。如果您在日志中查找,则可能会发现另一个错误,可能是您的doInBackground()方法中的一个错误,AsyncTask这使您的电流Activity爆炸,因此一旦AsyncTask回来,您就知道了。其他一些用户已经在这里解释了:-)


22
有时在那种情况下,我看不到真正的例外。要找到真正的异常,只需注释一下progressDialog.show()并再次运行该应用程序即可。现在您看到了。

嗨伙计!正如@Stuck所说,我也看不到真正的异常,我做了什么?我跟踪它用的断点,我发现,我所用的方法中的应用程序类的引用doInBackground中的AsyncTask中类,但没有它声明AndroidManifest文件中使用的属性android:name如下:android:name="my.package.MyApplicationClass"。使用AsyncTask它的一个好习惯总是记住要在方法内部实例化警报onPreExecute并将其关闭onPostExecute
GFPF

66

我错误地调用hide()而不是在dismiss()上触发了此错误AlertDialog


4
确实发生在我身上。同样,调用hide()然后将对话框设置为null也不是有效的选择。
卢卡斯·图里奥

我真的知道这背后的问题。但是调用dismiss()可以帮助我!
Karoly

59

您可以通过一个简单/愚蠢的错误来获得此异常,例如,如果您错过了switch语句中的break调用语句,则finish()在显示a之后意外调用(例如)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仍会显示!

因此,当您专心盯着代码,寻找不良的线程问题或复杂的编码等时,请不要对树木视而不见。有时,它就像丢失的break语句一样简单而愚蠢。:)


或多或少正是我的问题。创建对话框后,在onError中调用finish,而不在关闭按钮的onClick中调用finish。
jbass

45

这个问题的答案都是正确的,但是让我真正理解为什么有点困惑。在玩了大约2个小时后,出现此错误的原因(以我为例)打了我一下:

通过阅读其他答案,您已经知道has X has leaked window DecorView@d9e6131[]错误表示关闭应用程序时打开了对话框。但为什么?

对话框打开时,您的应用可能因其他原因崩溃了

由于代码中的某些错误,这导致您的应用程序关闭,由于其他错误,导致对话框在您的应用程序关闭的同时保持打开状态。

因此,请仔细阅读您的逻辑。解决第一个错误,然后第二个错误将自行解决在此处输入图片说明

一个错误会导致另一个错误,而另一个会导致另一个错误,例如DOMINOS!


2
不能相信这只有一个给予好评..或者我们在编程只是非常糟糕哈哈哈我也喜欢你的多米诺骨牌的比喻
user2161301

解决第一个错误,第二个错误将不会发生。这个比喻帮助了我。
itabdullah

这是不完全正确的,像电话旋转这样的实例也可能导致“活动”旋转发生。
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,这将在您查询null对话框的状态时引发错误
Jonathan Dunn

1
不,它不会@JonDunn,因为如果第一个布尔值为假,Java将不会处理第二个布尔值
matdev

13

这可能会有所帮助。

if (! isFinishing()) {

    dialog.show();

    }

2
在数百个类似的答案中,没有人显示如何检查窗口是否存在。因此,您节省了我一些时间来找到解决方法。谢谢。
kolyaseg

11

我有同样晦涩的错误消息,也不知道为什么。根据先前答案的线索,我将非GUI调用mDialog.finish()更改为mDialog.dismiss(),错误消失了。这并没有影响我的小部件的行为,但令人不安,很可能一直在标记重要的内存泄漏。


注意,在finish()调用之前,我正在执行mDialog.hide()。将其更改为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()和设置visibilityGONE。这样,我可以解决“ Activity has leaked window”日志错误问题。


我也面临着同样的问题。我在代码中添加了这些代码行,但无法正常工作,并给出了相同的错误“最初添加的android.view.WindowLeaked”,也无法播放视频并显示“视频无法播放”
User42590

10

我遇到了同样的问题,找到了此页面,尽管情况不尽相同,但在定义警报框之前,我finish从一个if块调用了它。

因此,简单地打电话dismiss是行不通的(因为尚未发出),但是在阅读了Alex Volovoy的答案并意识到这是引起它的警报框之后。我试图在该if块内部完成后立即添加return语句,从而解决了该问题。

我以为一旦打完电话,它就会停止一切并在那里完成,但事实并非如此。它似乎到达了其中的代码块的结尾,然后完成了。

因此,如果您想实现一种情况,有时它会在执行一些代码之前完成,那么您必须在完成后立即放一个return语句,否则它将继续运行,并像结束时那样调用finish。代码块不在您调用的地方。这就是为什么我遇到所有这些奇怪的错误的原因。

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();,因此它会说在您使对话框出现后立即完成就泄漏了窗口,即使那是并非如此,它仍然认为是。

我以为我会在这里添加它,因为这表明finish命令的行为与我认为的有所不同,我猜想还有其他人会与我发现之前的想法相同。


7

这不是问题的答案,而是与主题相关。

如果活动已在清单中定义了属性

 android:noHistory="true"

然后在执行onPause()之后,活动上下文将丢失。因此,所有使用上下文的视图都可能会出现此错误。


您可以将progessdialog.show()..和progressdialog.hide()in asynctask相同活动中 的类似内容关联起来,而不是onPause()来自activity??吗?看看我的问题... stackoverflow.com/questions/39332880/…–
Bhuro

1
它为我完美地工作:android:noHistory =“ true”
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时我完成了一个Activity。

因此,首先隐藏对话框,然后完成活动。


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

当我使用ProgressDialogin 时,这发生在我身上AsyncTask。其实我在使用hide()方法onPostExecute。基于@Alex Volovoy的答案,我需要在onPostExecute中使用dismiss()with ProgressDialog并将其删除。

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

progressDialog.dismiss(); // Use it

这并不是真正的完整答案。有两种泄漏对话框的方法。1)如果您有一个,AsyncTask并且显示Dialog,则发生了一些使Activity调用发生的事情onPause()(可能是AsyncTask本身中的某些逻辑,例如一个侦听器,那么它将泄漏。)2)如上所述,Dialog使用that创建的Activity Context永远不会被解雇,继续Activity前进。
tricknology

5

有效Activity has leaked window that was originally added...后,如果您尝试显示警报,则会发生“ ”错误Activityfinished

您有两个选择AFAIK:

  1. 重新考虑您的警报登录:dismiss()dialog实际退出你的活动之前。
  2. 将其dialog放在其他线程中并在该线程上运行thread(与current无关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,你应该dismissonPostExecute的方法。


4

最好的解决方案是在发生异常时在尝试捕获和关闭对话框中添加对话框

只需使用下面的代码

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

3
是不是对话框在调用完成后会为null ?,我认为dialog.dismiss()也会产生错误
Ashu Kumar,

3

就我而言,原因是我忘记在Android清单文件中包含权限。

我怎么知道的?好吧,就像@Bobby在接受的答案下方的评论中说的那样,只要向上滚动到您的日志,您就会看到真正引发异常的第一个原因或事件。显然,消息“活动最初已添加的窗口已泄漏”仅是由第一个异常引起的异常。


3

尝试下面的代码,它将在您关闭进度对话框时随时起作用,并且将查看其实例是否可用。

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

2

最好的解决方案是在显示progressbarprogressDialog

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

  //Show Your Progress Dialog

}

这对我不起作用。我收到来自HTTP调用的响应后出现了Dialog.show(),与此同时,我旋转屏幕时,活动处于分离状态,但是在Dialog.show()之前似乎isisn == true,尽管进行了此检查,但Dialog还是崩溃了
MichałZiobro

1

只要确保您的活动不会由于代码中某些地方引发的异常而意外关闭即可。通常,它发生在异步任务中,即当活动在doinBackground方法中面临强制关闭,然后asynctask返回到onPostexecute方法时。


1

我对此有另一种解决方案,并且想知道它对您是否有效:我正在扩展ProgressDialog,而不是在似乎是领先解决方案的onDestroy中解散了。

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,因为您不必以成员身份持有进度对话框,只需触发(显示)并忘记

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.