活动泄漏窗口 - Android

25

看一下这些代码:

在Android上自定义视图和窗口属性

问题

当我点击“主页按钮”时,会抛出一个异常:从这行代码中泄漏了Activity的窗口...

localWindowManager.addView(colourView, layoutParams);

问题:

你知道是什么原因导致的吗?

当我使用返回按钮关闭应用程序时,问题不会发生。

异常/错误日志:

W/InputManagerService(   96): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy@40908148 (uid=10056 pid=1368)
D/CordovaActivity( 1368): CordovaActivity.onDestroy()
D/CordovaWebView( 1368): >>> loadUrlNow()
E/WindowManager( 1368): Activity com.phonegap.helloworld.HelloWorld has leaked window pl.edu.uj.tcs.student.xxx.Display$Layer@40589368 that was originally added here
E/WindowManager( 1368): android.view.WindowLeaked: Activity com.phonegap.helloworld.HelloWorld has leaked window pl.edu.uj.tcs.student.xxx.Display$Layer@40589368 that was originally added here
E/WindowManager( 1368):         at android.view.ViewRoot.<init>(ViewRoot.java:258)
E/WindowManager( 1368):         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
E/WindowManager( 1368):         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/WindowManager( 1368):         at android.view.Window$LocalWindowManager.addView(Window.java:424)
E/WindowManager( 1368):         at pl.edu.uj.tcs.student.xxx.Display.setColorsViews(Display.java:181)
E/WindowManager( 1368):         at pl.edu.uj.tcs.student.xxx.Display$3.run(Display.java:139)
E/WindowManager( 1368):         at android.os.Handler.handleCallback(Handler.java:587)
E/WindowManager( 1368):         at android.os.Handler.dispatchMessage(Handler.java:92)
E/WindowManager( 1368):         at android.os.Looper.loop(Looper.java:130)
E/WindowManager( 1368):         at android.app.ActivityThread.main(ActivityThread.java:3683)
E/WindowManager( 1368):         at java.lang.reflect.Method.invokeNative(NativeMethod)
E/WindowManager( 1368):         at java.lang.reflect.Method.invoke(Method.java:507)
E/WindowManager( 1368):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
E/WindowManager( 1368):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
E/WindowManager( 1368):         at dalvik.system.NativeStart.main(Native Method)

D/CordovaActivity( 1368): onMessage(onPageStarted,about:blank)
D/CordovaWebViewClient( 1368): onPageFinished(about:blank)
D/CordovaActivity( 1368): onMessage(onPageFinished,about:blank)
D/CordovaActivity( 1368): onMessage(exit,null)
I/power   (   96): *** set_screen_state 0

编辑:

我该如何在Cordova Activity的onPause()、onStop()等函数中添加内容?

编辑2:

为什么这成为了一个问题呢?因为我所创建的只有一个扩展CordovaPlugin和一些辅助类的类。那就是全部了。我无法(我想)修改Activity类的主体。我能做的只有通过调用cordova.getActivity()函数来获取对它的引用。


请附上来自Logcat的完整堆栈跟踪。 - ntv1000
5个回答

48

什么是程序中的泄漏?

你获取但未释放的内存会导致内存泄漏。类似的情况也会发生在(windows/dialogs)。

这里发生了什么?

您正在尝试添加一个窗口,当它显示出来时它在前景,但当您按下主页按钮时,它被暂停,然后停止(尝试在onStop()和onPause()中放置一个toast)。

由于您没有告诉系统删除您的视图,因此它仍然附加到已从应用程序中消失/分离的窗口上。因此,根据系统,您的customView占用了它没有释放的空间。

解决方案

在您的onStop()或onPause()onDestroy()内确保解除您的视图(如果是对话框,则使用dismiss()),或者将其移除(如果使用窗口管理器添加,则使用remove())。

在您的on unload函数中添加dismiss或remove函数,因为您提到按下返回按钮时会出现此错误。退出应用程序时会调用其onUnload()方法。

建议(如果不相关请忽略)

我注意到您正在尝试制作一个系统警报窗口,该窗口会覆盖其下方的所有内容。在活动中添加此类弹出窗口是有风险的,因为它可能导致泄漏问题。您实际上可以通过一个 Service 添加此类窗口,以便它超越您的活动并在设备上的任何地方显示(如果这是您需要的)。

看看这个

更新2-Cordova生命周期

为什么不尝试在CordovaPlugin类中重写onUnload方法?我试图查找,但文档提到了onPause和onResume方法的存在。如果您在CordovaPlugin类中得到了onUnload,则可以在您的view类runOnUiThread方法中删除您正在创建的视图。


没有冒犯的意思,但我不理解你的编辑注释。它对我来说有些模糊不清。请更具体一些,这样我才可以更容易地帮助你。 - cafebabe1991
你能否发布你的完整活动和 Cordova 类的代码? - cafebabe1991
https://github.com/mrfesol/DisplayPlugin/blob/master/src/pl/edu/uj/tcs/student/tomaszwesolowski/Display.java - tomwesolowski
为什么不尝试在CordovaPlugin类中覆盖onUnload方法。我试图查找,但文档提到了onPause和onResume方法的存在。如果你在CordovaPlugin类中有onUnload,则可以在runOnUiThread方法中删除你正在创建的视图类的视图。 - cafebabe1991
哦,我之前没有注意到。谢谢。如果您在接下来的15小时内发布答案,您将获得奖励。 - tomwesolowski

11
你试图在退出活动后显示一个对话框。
解决方法是在退出活动之前,在onPause()中调用你创建的对话框上的dismiss()。所有窗口和对话框都应在离开活动之前关闭。
@Override
 protected void onStop() {
  super.onStop();
  if (loadingDlg != null) {
   loadingDlg.dismiss();
   loadingDlg = null;
  }
}

希望这对你有所帮助。

Activity-has-leaked-window-that-was-originally-added


记录一下,我之前遇到过这个问题。由于对话框是通过回调显示的时间安排,除了在尝试显示对话框时捕获异常并压制它之外,可能没有其他办法(除非您要尝试使用活动状态同步所有回调)。 - user695992
https://github.com/mrfesol/DisplayPlugin/blob/master/src/pl/edu/uj/tcs/student/tomaszwesolowski/Display.java - tomwesolowski

3
检查对话框是否正在显示
@Override
  protected void onStop() {
    super.onStop();
if (loadingDlg != null) {

        if(loadingDlg.isShowing())
        loadingDlg.dismiss();

        loadingDlg = null;
 }
}

0
我有一个finish()在我的AlertDialog被调用之前被调用,导致Activity在AlertDialog被调用之前结束。我将finish()移除,并在用户完成输入后使用AlertDialog再放置它,这样就解决了窗口泄漏的问题。

0

泄露的窗口通常发生在您的上下文显示对话框并且该上下文突然被强制关闭而您的对话框尚未正确解除。

为了解决这个问题,您必须在窗口泄漏错误之前修复错误。


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