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

1284

这个错误是什么,为什么会出现?

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)

8
另一个经典问题是屏幕方向改变时的处理方法:https://dev59.com/inNA5IYBdhLWcg3wC5Th - rds
49个回答

1707

在退出Activity后,您试图显示一个对话框。

[编辑]

这个问题是android开发者中搜索排名靠前的问题之一,因此从评论中添加了一些重要的观点,这可能更有帮助,而不必深入评论交流。

答案1:

在退出Activity后,您试图显示一个对话框。

答案2:

在某些情况下,这个错误可能会有点误导(尽管答案仍然完全正确) - 即在我的情况下,在AsyncTask中抛出了一个未处理的异常,导致Activity关闭,然后打开的进度对话框引起了这个异常... 因此“真正”的异常在日志中早一些

答案3:

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


4
@Override public void onStop() { if (dialog != null) { dialog.dismiss(); dialog = null; } } - Md.Tarikul Islam
27
即使过去8年了,这仍然很相关!我遇到了异常,因为当它试图显示我的AlertDialog时,该活动已经关闭了(因此是Answer 2)。最终我发现应用程序将一个“null”对象添加到场景中(本不应该发生,但确实发生了),但它没有为此提供额外的异常,整个问题被“泄漏的窗口”异常掩盖了。 - Neph
在onStop()中是否有可能扫描所有打开的对话框并将它们全部关闭?当单击项目时,我在ListView中生成对话框。我不确定如何从onStop中检索它们的引用。 - Myoch
3
答案3是最好的解决方案。对我非常有效。谢谢kaze,Alex! - amit bansode
在处理问题3时,StackTrace并不是触发异常的代码,而是显示对话框的位置。这非常具有误导性。 - undefined
显示剩余5条评论

424

解决方法是在退出Activity之前,在viewP.java:183中创建的Dialog上调用dismiss(),例如在onPause()中。所有WindowDialog在离开一个Activity之前都应该关闭。


5
当用户旋转手机时,所有的对话框都应该被关闭吗?这听起来不太对。 - LarsH
@LarsH,正如您所看到的,我的答案是在7年前写的,那时候肯定是正确的。我现在不再从事Android开发,但根据我在文档中看到的内容,这可能仍然是正确的,但自那以来,Android已经取得了长足的进步(引入了Fragment只是其中之一),所以现在可能更容易了。 - molnarm

115
如果您正在使用 AsyncTask,那么这条日志信息可能会误导您。如果您在日志中查找,可能会发现另一个错误,可能是由于您的 AsyncTaskdoInBackground() 方法中的某个错误导致当前的 Activity 崩溃,因此一旦 AsyncTask 返回...嗯,您就知道剩下的了。其他一些用户已经在这里解释过了 :-)

26
有时在这种情况下,我无法看到真正的异常。要找到真正的异常,请注释掉 progressDialog.show() 并重新运行应用程序...现在你会看到它。 - Stuck
大家好!如@Stuck所提到的,我无法看到真正的异常是什么,我该怎么办?我使用断点跟踪发现,在“AsyncTask”类中的“doInBackground”方法中使用了“Application”类的引用,但没有在“AndroidManifest”文件中声明它,也没有使用属性“android:name”进行声明,就像这样:android:name="my.package.MyApplicationClass". 当使用“AsyncTask”时,一个好习惯是始终在“onPreExecute”方法中实例化警报,并在“onPostExecute”中解除它。 - GFPF

80

我因错误地在AlertDialog上调用hide()而不是dismiss()而引发了这个错误。


5
完全发生在我身上了。此外,调用hide()然后将对话框设置为null也不是一个有效的替代方案。 - Lucas Tulio
我真的想知道这背后的问题。但是调用dismiss()帮助了我! - narancs

65

你可能会因为一些简单/愚蠢的错误而遇到这个异常,例如在显示AlertDialog后意外调用finish(),或者漏掉了switch语句中的break调用语句...

   @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;
        }
    }
< p > finish() 方法会关闭当前的 Activity,但是 AlertDialog 仍在显示!

所以,当您专注于代码并寻找线程问题或复杂编码等时,请不要忘记整体思路。有时候问题可能只是简单愚蠢的缺少了Break语句。 :)


基本上就是我的问题。在创建对话框后,在dismiss按钮的onClick中没有调用finish,而是在onError中调用了它。 - jbass

65
这个问题的答案都是正确的,但对我来说有点难理解为什么会出错。经过大约两个小时的尝试,我意识到了这个错误(在我的情况下)的原因:
从阅读其他答案中,您已经知道,X has leaked window DecorView@d9e6131[] 错误表示当您的应用程序关闭时有一个对话框处于打开状态。但为什么?
可能是因为您的应用程序在对话框打开时由于某些代码错误而崩溃,导致该对话框保持打开状态,同时您的应用程序由于另一个错误而关闭。
所以,请仔细检查您的逻辑。解决第一个错误,然后第二个错误就会自行解决。一个错误引起了另一个错误,就像多米诺骨牌!
请参考以下链接查看图片:enter image description here

4
难以置信这只有一个赞,或者我们只是在编程方面真的很差笑,我也喜欢你的多米诺骨牌比喻。 - user2161301
解决第一个错误,第二个错误就不会再出现了。这个类比对我很有帮助。 - itabdullah
2
这并不完全正确,例如手机旋转也会导致“活动”旋转发生。 - Sreekanth Karumanaghat
优秀的解释 (y) - M.Fakhri

39

在退出一个Activity后尝试显示对话框时会出现此问题。

我刚刚通过编写以下代码解决了这个问题:

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

基本上,从你启动progressDialog的类开始,重写onDestroy方法并按照以下方式处理。 这解决了“Activity has leaked window”问题。


onDestroy不能保证被调用。最好将该代码放在onPause或onStop中。 - Hanu

22

我最近也遇到了同样的问题。

这个问题的原因是在对话框被关闭之前活动已经结束。导致这种情况发生的原因有很多。上面帖子中提到的原因也是正确的。

我遇到了一个情况,因为在线程中调用了一个会抛出异常的函数,导致窗口被关闭,所以发生了异常。


20

这可能有帮助。

if (! isFinishing()) {

    dialog.show();

    }

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

19

当 activity 销毁时关闭对话框。

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

如果pDialog为null,这将会抛出一个错误,因为您正在查询空对话框的状态。 - Jonathan Dunn
1
不会的,@JonDunn,因为如果第一个布尔值为false,Java将不会处理第二个布尔值。 - matdev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接