webview内存泄漏解决方案
1.运行app,先用AS自带的Profiler分析我们的WebViewActivity,频繁进出,看内存占用情况,会发现内存在不断的上升,而且退出当前页面内存只是下降一点,一直持续下去,肯定会OOM;
2.引入leakcanary内存泄漏分析工具
由于只运行debug模式来检测,所以只需在build.gradle中引入:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
然后在自定义的Application的OnCreate方法中加入如下:
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
LeakCanary.install(this);
接下来重新编译运行APP,继续频繁进出WebviewActivity,LeakCanary会很快检测出内存泄漏风险,等待通知栏下载hprof文件成功,然后点击Android Studio 页面右下角'Device File Explorer',会显示当前手机的文件夹,
找到"sdcard--->Download--->leakcanary-com.xxx.xxx(后缀是自己包名的文件夹)--->2020-09-29_10-06-28_940.hprof",找到这个文件保存在电脑本地,然后使用工具分析,这里分析的的方式有很多种:
1.直接使用AS打开,会自动fetch然后可以查看各变量类型使用情况;
2.使用Eclipse的Eclipse Memory Analyzer;
3.使用在线分析工具:https://heaphero.io/heap-index.jsp#header(个人比较喜欢使用这个);
接下来直接按照第三个方式来举例了:
这是分析的整体结果图:
然后查看Large objects,会发现webview和drawable占用内存较高,一步步点进去 会发现是Bitmap的buffer导致的内存泄漏风险
那么再回想一下WebViewActivity的布局原来有一张无网的背景图在WebViewActivity频繁进出时没有及时回收导致的(Android5.1和Android8.0检测结果还有差异)。那就开始优化之路--及时回收ImageView组件和Bitmap:
// ivNoNetwork是无网的ImageView组件
if(ivNoNetwork!= null ){
Drawable drawable = ivNoNetwork.getDrawable();
if (drawable != null && drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap != null && !bitmap.isRecycled()) { // 如果还没被回收,才去回收
bitmap.recycle();
}
}
}
// 同时在父布局中移除这个ImageView, llNoNetwork是ImageView组件的父布局
if(llNoNetwork != null){
llNoNetwork.removeView(ivNoNetwork); //必须是直接remove它,如果使用removeAllView方法,当很快速度频繁进出时,效率太慢 还是会报leak
}
ivNoNetwork = null;
然后重新运行再检测,就不会再报内存泄漏风险了。
再说一下Webview的常规优化方案:
1.使用动态添加Webview的方式
// 动态添加Webview
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
WeakReference weakReference = new WeakReference(this); //使用弱引用去持有当前Activity
X5WebView webView = new X5WebView((Context) weakReference.get(),null);
webView.setLayoutParams(params);
llwebLayout.addView(webView);
2.注册的服务、监听器、handler要及时移除并置为null
3.如果当前页面有ImageView,也要及时回收、销毁
4.最后再执行super.onDestroy()方法
@Override
protected void onDestroy() {
try{
if(mMyRevicer != null){
unregisterReceiver(mMyRevicer);
mMyRevicer = null;
}
if(llwebLayout != null){
llwebLayout.removeAllViews();
}
// webView清除缓存并销毁
if (webView != null) {
webView.stopLoading();
webView.clearHistory();
webView.removeAllViewsInLayout();
webView.removeAllViews();
webView.setWebViewClient(null);
webView.destroy();
webView = null;
}
// 那张无网背景大图,主动回收
if (ivNoNetwork != null) {
Drawable drawable = ivNoNetwork.getDrawable();
if (drawable != null && drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
}
}
if (llNoNetwork != null) {
llNoNetwork.removeView(ivNoNetwork); //ImageView的父组件必须是直接remove当前ImageView
}
ivNoNetwork = null;
llNoNetwork = null;
llwebLayout = null;
mClickListener= null;
}catch (Throwable throwable){
throwable.printStackTrace();
} finally {
super.onDestroy();
}
}
如果你使用的是腾讯的X5Webview,在Activity的onDestory方法中最好不要使用这个方法,源码中可以查看到它会new一个新的webview,虽然方法结尾会置空为null。
//官方文档介绍这个API是:一次性删除所有缓存
// QbSdk.clearAllWebViewCache(this,true);
这个是X5Webview SDK的源码:(基于implementation 'com.tencent.tbs.tbssdk:sdk:43939')
public static void clearAllWebViewCache(Context var0, boolean var1) {
TbsLog.i("QbSdk", "clearAllWebViewCache(" + var0 + ", " + var1 + ")");
boolean var2 = false;
WebView var3;
try {
var3 = new WebView(var0);
if (var3.getWebViewClientExtension() != null) {
var2 = true;
u var4 = com.tencent.smtt.sdk.u.a();
if (null != var4 && var4.b()) {
var4.c().a(var0, var1);
}
}
var3 = null;
} catch (Throwable var6) {
TbsLog.e("QbSdk", "clearAllWebViewCache exception 2 -- " + Log.getStackTraceString(var6));
}
...
}
以上即是本人解决Webview 内存泄漏的一些个人心得,希望对你有所帮助~
本文地址:https://blog.csdn.net/qq_33539839/article/details/108866646
上一篇: rmvb格式视频怎么转换成wav格式?