有些东西还是记下来比较好,记记随笔,欢迎批评建议。
前段时间在项目中就用到webview展示大量的新闻资讯页面,然后就惊喜的出现内存泄漏了,于是乎我在网上查了一些资料然后在这里总结一下解决方法,欢迎拍砖。
(方法4划重点)。
Android混合开发时经常用到WebView加载html等页面,而WebView的内存泄漏就是最经常遇到的问题,尤其是当项目中需要用webview加载的页面比较多时。
即使当我退出页面时在我的BrowserActivity的onDestroy()方法中进行内存占用回收(如下图)但并没有效果:
mWebView.removeAllViews();
mWebView.destroy();
mWebView=null;
当我点开了多少条新闻内存中就存在多少个BrowserActivity的实例,说明我退出时这个BrowserActivity没有被回收,这样的话当我浏览的新闻比较多时,内存就会累积存在一定的OOM风险,而且新闻界面一般存在大量图片,所以这个问题是必须要解决的。
1. new一个而不是在.xml中定义webview节点
attention:最初在写这篇的时候这一小节可能写的不够严谨,要是造成误解真是抱歉;写这篇小结时的目的也是想把知道的一些解决方法记下来方便自己查看,没想到能收到评论和质疑,我还是很开心的,但是通过这个我也发现,发出来的东西还是要写的严谨一些,会慢慢改进的。所以这一小节重新说明了一下,要是有不对的地方还是欢迎大家拍砖。
不要在布局文件中定义webview的节点,而是在需要的时候动态生成。你可以在需要webview的布局位置放一个LinearLayout,需要时在代码中动态生成webview并add进去:
//mWebView=new WebView(this);
mWebView=new WebView(getApplicationContext());
LinearLayout linearLayout = findViewById(R.id.xxx);
linearLayout.addView(mWebView);
然后在onDestroy()方法中调用:
@Override
protected void onDestroy() {
if( mWebView!=null) {
mWebView.setVisibility(View.GONE);
mWebView.removeAllViews();
mWebView.destroy();
}
super.onDestroy();
}
tips: 关于创建webview时new WebView(...);到底是传入ApplicationContext还是Activity的context,说法不一,但是网上较为一致的观点是采用application的context。
传ApplicationContext貌似可以防止webview对activity的引用而造成的内存泄漏;但是在很多情况下会报错,但是这个出错应该是webview的某些特殊动作产生由Application到Activity的类型转换错误;
采用activity的context细想来貌似和在xml中直接定义没有什么区别;
2. 手动删除引用
这个方法在我的项目中没有效果,但原文博主说在他的项目中效果很好,也许对其他人的情况有效,在这里也记下来。
public void setConfigCallback(WindowManager windowManager) {
try {
Field field = WebView.class.getDeclaredField("mWebViewCore");
field = field.getType().getDeclaredField("mBrowserFrame");
field = field.getType().getDeclaredField("sConfigCallback");
field.setAccessible(true);
Object configCallback = field.get(null);
if (null == configCallback) {
return;
}
field = field.getType().getDeclaredField("mWindowManager");
field.setAccessible(true);
field.set(configCallback, windowManager);
} catch(Exception e) {
}
}
然后在activity中调用:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setConfigCallback(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
}
public void onDestroy() {
setConfigCallback(null);
super.onDestroy();
}
3. 进程
为加载WebView的界面开启新进程,在该页面退出之后关闭这个进程。
这个方法我没有测试,不知道应用和效果如何,有兴趣的可以试试。
4. 从根源解决(划重点)