标签:
(该文章,引自零号路的私人博客,本人在浏览框架的开发过程中,用该方式,规避了内存泄露的问题。)
在Android5.1系统中,会发现App存在 WebView 泄漏情况,还比较严重。并且只是发生在 Android 5.1 系统。
GC roots 如下:
每新打开一次这个WebViewActivity,就会发生就会发生一次改Webview实例无法释放,新增一个对象。
上图中的两个 AppSearchWebView实例,就是由于打开了两次导致。
出现了这个问题分析起来还是比较简单的,根据这个引用关系,我们可以直观的看到是由于 Appsearch(extends Application)的 mComponentCallbacks 一直在强引用AWComponentCallbacks,导致无法释放。然后AWComponentCallbacks -> AWContents > AppSearchWebView。
通过分析代码发现关键在于 AwContents 这里的 AwComponentsCallbacks 为什么没有释放。
@Override
public void onAttachedToWindow() {
if (isDestroyed()) return;
if (mIsAttachedToWindow) {
Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
return;
}
......
mComponentCallbacks = new AwComponentCallbacks();
mContext.registerComponentCallbacks(mComponentCallbacks);
}
@Override
public void onDetachedFromWindow() {
if (isDestroyed()) return;
if (!mIsAttachedToWindow) {
Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
return;
}
......
if (mComponentCallbacks != null) {
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mComponentCallbacks = null;
}
......
}
看这段代码看不出来什么问题,onAttach的时候 register,detach的时候 unregister, 不会存在问题。
但是为什么呢?
难道是由于 if (isDestroyed()) return 这条return引起的?
当调用 Webview.destroy() 后 这个判断 返回true。
我们看下哪里调用了 webview.destroy()
// source from WebViewActivity
@Override
protected void onDestroy() {
super.onDestroy();
if (mWebView != null) {
mWebView.destroy();
}
}
很多应用应该都是这么做的,包括系统浏览器,在Activity destroy的时候,调用 webview的destroy。并且一直工作的很好。
通过调试发现,确实是由于此调用导致的。onDestroy 发生在 onDetach 之前。
那为什么 android 5.1 之前的代码没有问题呢?
看下代码:
// AwContents.java
@Override
public void onDetachedFromWindow() {
if (!mIsAttachedToWindow) {
Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
return;
}
......
if (mComponentCallbacks != null) {
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mComponentCallbacks = null;
}
......
}
相对于 5.1 的代码少了那句 if (isDestroyed()) return;
解决方案可以:在destroy之前,把webview 从 parent 中 remove 掉,同样可以提前detach。
protected void onDestroy() {
if (mWebView != null) {
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
标签:
原文地址:http://blog.csdn.net/zhangcanyan/article/details/51344118