【Android 性能优化:内存篇】——WebView 内存泄露治理

这篇具有很好参考价值的文章主要介绍了【Android 性能优化:内存篇】——WebView 内存泄露治理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景:笔者在公司项目中优化内存泄露时发现WebView 相关的内存泄露问题非常经典,一个 Fragment 页面使用的 WebView 有多条泄露路径,故记录下。

Fragment、Activity 使用WebView不释放

项目中一个Fragment 使用 Webview,在 Fragment onDestroyView 时候却没有释放,释放 WebView 还不简单嘛,于是笔者在 Fragment 的 onDestroyView 补充了如下代码:

if (webView != null) {
  ViewGroup parent = (ViewGroup) webView.getParent();
  if (parent != null) {
    parent.removeView(webView);
  }
  webView.destroy();
  webview = null;
}

然而,这样其实释放不全,还是抓到其他的泄露路径

安卓 view内存泄漏,性能优化,android,性能优化

如图GC 引用链:AwContents->WebVIew->View.LinsenerInfo->WebViewFragment

原因是使用 WebView的时候,注册了OnFocusChangeListener

webView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
  @Override
  public void onFocusChange(View v, boolean hasFocus) {
    //省略
  }
});

因此,释放 WebView的时候,还需要把注册的一些Listener 释放

WebView 释放不全

上面介绍了释放 WebView 资源的时候释放不全的例子,那么怎样才能将用到的WebView 资源释放完全呢?

笔者封装了一个接口如下:

public void destroyWebView(WebView webView) {
  try {
    if (webView != null) {
      ViewGroup parent = (ViewGroup) webView.getParent();
      if (parent != null) {
        parent.removeView(webView);
      }
      webView.setOnTouchListener(null);
      webView.setOnKeyListener(null);
      webView.setOnFocusChangeListener(null);
      webView.setWebChromeClient(null);
      webView.setWebViewClient(null);
      webView.loadUrl("about:blank");
      webView.onPause();
      webView.removeAllViews();
      webView.destroyDrawingCache();
      webView.destroy();
      webView = null;
    }
  } catch (Throwable e) {
    e.printStackTrace();
  }
}

这样释放真的释放完全了?如果你使用的WebView 还注册了其他的Listener,记得也需要释放

网上,还有说需要调用

webView.pauseTimers();
webView.clearHistory();

上面的接口慎用,因为它们是对全局生效的,不只当前WebView!

按上面两个步骤解决完,笔者以为不会再发生泄漏,谁知道还是抓到第三条泄露路径!!

安卓 view内存泄漏,性能优化,android,性能优化

GC 引用链:AwContents->BannerView->Banner->CardView->Container->AdView->匿名内部类AdListener->WebViewFragment

匿名内部类导致 WebView泄露

按上面描述的引用链,匿名内部类隐式持有外部类 Fragment 的引用,而这个匿名内部类AdShowListener 刚好是 AdView 持有的, AdView 本质上是一个 WebView.

解法很常规:把匿名内部类改为静态内部类,然后静态内部类里使用的 Fragment 改为弱引用,并且 Fragment 销毁的时候,AdShowListener 置空。

到此,笔者以为不会再发生内存泄露了,怎知,还是抓到了,这次抓的是包裹 Fragment 的Activity 作为 Context 被 webview 持有

安卓 view内存泄漏,性能优化,android,性能优化

意不意外,惊不惊喜?

GC 引用链:AwContents->WebView->WebViewActivity, WebViewActivity 作为 Conext 被 WebView 持有

因为 Fragment 初始化 WebView 的时候 使用了 getActivity(),context 一直被 WebView 内核持有,笔者猜测部分系统会有这种问题。这种问题是否无解了?山重水复疑无路,柳暗花明又一寸,笔者意外发现有个类 MutableContextWrapper 可以使用。

MutableContextWrapper 切换 Context

初始化 WebView 的时候使用AppContext,在 Activity 使用 Webview 的时候切换为 Activity,最后销毁 WebView 之前再切换回 AppContext

为什么在Activity 使用WebView的时候切换到Activity 呢?因为WebView 中的可能有些场景依赖 Activity 如:弹窗Dialog,Context 为AppContext 会发生崩溃。

private WebView webview;
//初始化Webview
MutableContextWrapper contextWrapper = new MutableContextWrapper(getAppContext());
webview = new WebView(contextWrapper);

//在Activity中使用
private WebView acquireWebView(Activity activity) {
    //缓存中的webview
    MutableContextWrapper contextWrapper = (MutableContextWrapper) webView.getContext();
    contextWrapper.setBaseContext(activity);
   return webView;
}

//销毁之前
  public void recycleWebView(WebView webView) {
    if (webView == null) {
      return;
    }
    MutableContextWrapper contextWrapper = (MutableContextWrapper) webView.getContext();
    contextWrapper.setBaseContext(getAppContext());
    destroyWebView(webview);
  }

//销毁 webview 的接口
public void destroyWebView(WebView webView) {
  try {
    if (webView != null) {
      ViewGroup parent = (ViewGroup) webView.getParent();
      if (parent != null) {
        parent.removeView(webView);
      }
      webView.setOnTouchListener(null);
      webView.setOnKeyListener(null);
      webView.setOnFocusChangeListener(null);
      webView.setWebChromeClient(null);
      webView.setWebViewClient(null);
      webView.loadUrl("about:blank");
      webView.onPause();
      webView.removeAllViews();
      webView.destroyDrawingCache();
      webView.destroy();
      webView = null;
    }
  } catch (Throwable e) {
    e.printStackTrace();
  }
}

至此,没有再抓到泄露路径。

总结

本文列举了项目中治理 WebView 内存泄露的手段:

1)Fragment、Activity 销毁时释放WebView。

2)释放WebView 需要释放完全,WebView 注册的各种监听器都需要释放。

3)同时要考虑Fragment、Activity 有没用到匿名内部类,如果有要改成静态内部类,并且要静态内部类有使用Fragment、Activity的话要使用弱引用。

4)初始化 WebView 的时候使用AppContext,在 Activity 使用 Webview 的时候切换为 Activity,最后销毁 WebView 之前再切换回 AppContext。文章来源地址https://www.toymoban.com/news/detail-765057.html

到了这里,关于【Android 性能优化:内存篇】——WebView 内存泄露治理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 开发必备知识点及面试题汇总(Android+Java+算法+性能优化+四大组件……),腾讯安卓开发面试

    5.请介绍下 AsyncTask的内部实现,适用的场景是 AsyncTask 内部也是 Handler 机制来完成的,只不过 Android 提供了执行框架来提供线程池来 执行相应地任务,因为线程池的大小问题,所以 AsyncTask 只应该用来执行耗时时间较短的任务, 比如 HTTP 请求,大规模的下载和数据库的更改不

    2024年04月15日
    浏览(19)
  • 【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题

    Jprofilers是针对Java开发的 性能分析工具(免费试用10天) , 可以对Java程序的 内存,CPU,线程,GC,锁 等进行监控和分析 , 本人IDEA版本是 2020.2.2 ,选择的Jprofiler版本是 12.0 (早期的版本是纯英文的, 12.0支持中文 ,安装主要考虑是否与IDEA插件兼容即可) 进入Jprofiler官网下载 - Jprofiler 版本这

    2024年02月19日
    浏览(11)
  • 安卓部分手机使用webview加载链接后白屏(Android低版本会出现的问题)

    大爷:小伙我这手机怎么打开你们呢这个是白屏什么都不显示。 大娘:小伙我这也是打开你们呢这功能,就是一个白屏什么也没有,你们呢的应用不会有病毒吧。 小伙:我的手机也正常; 同事:我的也正常可以显示; 小伙:你们都是什么手机型号; 大爷:我的Android7.1.1

    2024年04月15日
    浏览(8)
  • 安卓进阶(一)App性能优化

    性能优化的目的是为了让应用程序App 更快、更稳定 更省。具体介绍如下: 更快:应用程序 运行得更加流畅、不卡顿,能快速响应用户操作 更稳定:应用程序 能 稳定运行 解决用户需求,在用户使用过程中不出现应用程序崩溃(Crash) 和 无响应(ANR)的问题 更省:节省耗费

    2024年02月07日
    浏览(16)
  • linux 性能优化-内存优化

    CPU 管理一样,内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应 用程序的指令、数据、缓存等。 1.1.1.日常生活常说的内存是什么? 我的笔记本电脑内存就是 8GB 的 这个内存其实是物理内存 物理内存也称为主存,大多数计算机用的主存都是动态随机访问内

    2024年02月04日
    浏览(19)
  • Linux性能优化--性能工具:系统内存

    本章概述了系统级的Linux内存性能工具。本章将讨论这些工具可以测量的内存统计信息,以及如何使用各种工具收集这些统计结果。阅读本章后,你将能够: 理解系统级性能的基本指标,包括内存的使用情况。 明白哪些工具可以检索这些系统级性能指标。 每一种系统级Linu

    2024年02月07日
    浏览(10)
  • Linux性能优化--性能工具:特定进程内存

    本章介绍的工具使你能诊断应用程序与内存子系统之间的交互,该子系统由Linux内核和CPU管理。由于内存子系统的不同层次在性能上有数量级的差异,因此,修复应用程序使其有效地使用内存子系统会对程序性能产生巨大的影响。 阅读本章后,你将能够: 确定一个应用程序使

    2024年02月07日
    浏览(12)
  • linux性能优化-内存原理

    只有内核才可以直接访问物理内存,Linux内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程通过访问虚拟内存来访问内存。 虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同字长(也就是单个 CPU 指令可以处理数据的最

    2024年02月01日
    浏览(10)
  • 前端性能优化——内存问题

    过高的内存资源占用会导致 Web 应用变慢,甚至崩溃。可以通过 window.performance.memory 查看浏览器的内存限制等信息。 Web 前端开发中存在许多内存问题,下面是一些常见的内存问题: 内存泄漏:当一个对象不再被使用,但仍然占用着内存空间,就会导致内存泄漏问题。在 Web

    2024年02月16日
    浏览(15)
  • Unity 性能优化二:内存问题

    目录 策略导致的内存问题 GFX内存 纹理资源 压缩格式 Mipmap 网格资源 Read/Write 顶点数据 骨骼 静态合批 Shader资源 Reserved Memory RenderTexture 动画资源 音频资源  字体资源 粒子系统资源 Mono堆内存 1. Assetbundle 打包的时候,单个资源被重复打包,可以把依赖的资源,单个打包,通过

    2024年02月15日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包