webview性能优化—webview预创建
前言
如下图打开一个WebView通常会经历以下几个阶段:
上图中webview初始化阶段,对于用户来说是无反馈。当App首次打开时,默认是并不初始化浏览器内核的,只有当创建WebView实例的时候,才会创建WebView的基础框架。App中打开WebView的第一步并不是建立连接,而是启动浏览器内核。
webview初始化时间数据对比
首次打开时间 | 二次打开时间 |
---|---|
498ms | 142ms |
可以看出webview首次打开时间比二次打开时间3倍还多,初次打开webview时间长的原因是首次打开webview的时候要加载webview的内核。
webview预创建
由上面的对比可知,首次打开webview的时间是很长的,如果在业务打开webview的时候再创建webview加载url,打开的速度会比较慢。
可以在app初始化后,创建一个webview的缓存池,当业务需要使用webview的时候从缓存池中获取webview,由于缓存池中的webview是已经初始化了的,所以业务打开webview相当于二次打开webview。
由于webview只能在主线程中创建,可以在为了不影响冷启动性能,可以使用idleHandler方法在主线程空闲时创建webview
1、创建webview并缓存
fun preCreate(size: Int, application: Context) {this.size = sizeodysContext = MutableContextWrapper(application)createWebview()}mainMessageQueue?.addIdleHandler {//看下cacheWebs size中数量,如果cacheWebs的size比preCreate的size少,则创建webview并添加if (cacheWebs.size < size) {odysContext?.let {cacheWebs.add(SoftReference(WebView(it)))}}false}
- 上面cacheWebs中使用软引用来来存放webview的实例,这样在内存不足时可以进行释放,添加webview到缓存放在idleHandler中。
- 上面对context使用MutableContextWrapper进行一层包装,MutableContextWrapper可以替换context,因为预创建webview的时候不能使用activity的context(预创建的webview不属于任何activity,如果使用activity会内存泄漏),这里使用的是applicationContext进行webview初始化。
- MutableContextWrapper代码如下,提供了setBaseContext方法来设置context,这样在activity中获取webview时就可以进行替换了。
public class MutableContextWrapper extends ContextWrapper {public MutableContextWrapper(Context base) {super(base);}/*** Change the base context for this ContextWrapper. All calls will then be* delegated to the base context. Unlike ContextWrapper, the base context* can be changed even after one is already set.* * @param base The new base context for this wrapper.*/public void setBaseContext(Context base) {mBase = base;}
}
2、获取webview实例
在activity中获取webview实例,这里activity一般定义为webviewActivity,如下
/**** 获取缓存中的webview,这里的context必须是activity的context*/fun fetchCacheWebview(context: Context, index: Int): WebView? {return if (cacheWebs.isEmpty() || cacheWebs.size <= index) {//创建一个新的webviewWebView(context)} else {//拿到index的webview,并且移除掉cache中的这个webview,不然其他地方如果又拿了就出问题val ref = cacheWebs[index]cacheWebs.removeAt(index)//移除后再创建一个缓存的webview,保证缓存池中的webview数量不变createWebview()//这里替换掉webview的contextval web = ref.get()//replace contextreplaceContext(web, context)return web}}
注意获取cacheWebs中的activity时需要activity的context,并且使用replaceContext(web,context)
方法替换掉原来webview中的application context
private fun replaceContext(webView: WebView?, context: Context) {webView?.let {val cot = it.contextif (cot is MutableContextWrapper?) {cot.baseContext = context}}}
- 在获取到cacheWebs中的webview实例后,要将这个实例从cacheWebs中移除,防止其他地方再获取这个实例。
- 在移除cacheWebs中的webview实例后,要再往缓存中加webview实例,保证缓存池中webview的缓存数量。
3、activity中如何使用预创建的webview
正常来说webview的使用方式有在xml中定义webview,和动态添加webview。
1、往布局里面加WebView
<WebViewandroid:id="@+id/webview"android:layout_width="match_parent"android:layout_height="match_parent"
/>
2、动态添加webview
val webView = WebView(activityContext)
setContentView(webView)
- 由于要使用预创建的webview,所以直接在xml布局中添加webview的话就无法使用预创建的webview,因为xml中的元素解析生成对象是在
setContentView()
方法中,会在xml解析时自动生成webview对象。 - 如果想使用xml的方式并且使用预加载的webview,可以用下面的方式:
<FrameLayoutandroid:id="@+id/webviewContainer"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" />
然后在代码中进行如下设置:
//先获取预创建的webviewval webview=OdysManager.fetchCacheWebview(context,0)//将webview 添加到webviewContainer中webviewContainer.addView(webview, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT))
动态添加预创建的webview
//先获取预创建的webviewval webview=OdysManager.fetchCacheWebview(context,0)//将webview 添加到webviewContainer中setContentView(webview)
3、销毁webview
在activity的onDestory中对webview进行销毁,销毁webview时先替换掉webview的context为applicationContext如下:
override fun onDestroy() {super.onDestroy()//替换掉context并且销毁if (webView != null) {webView.stopLoading()replaceContext(webView, context)webView.loadUrl("about:blank")webView.destroy()}}
数据对比
以创建webview之前开始,到onPageStarted的时间戳统计数据如下
- 1、不使用预创建webview
机型 | 时间(ms) |
---|---|
Honor 20 | 648 |
Honor 20 | 624 |
Honor 20 | 593 |
Honor 20 | 565 |
Honor 20 | 515 |
2、使用预创建webview
机型 | 时间(ms) |
---|---|
Honor 20 | 350 |
Honor 20 | 297 |
Honor 20 | 310 |
Honor 20 | 323 |
Honor 20 | 254 |
代码仓库
https://github.com/hankinghu/odys
参考
1、https://tech.meituan.com/2017/06/09/webviewperf.html
webview性能优化—webview预创建相关推荐
- Android WebView 性能优化
原文出处:http://motalks.cn/2016/09/11/Android-WebView-JavaScript-3/ WebView相关阅读 Android WebView 和 javaSc ...
- WebView开发(三):WebView性能优化
一.Android WebView开发(一):基础应用 二.Android WebView开发(二):WebView与Native交互 三.Android WebView开发(三):WebView性能 ...
- WebView性能优化的那些事儿……
有个精通硬件,后台,前端的大神朋友最近想做一个Web APP,于是便来求助于我,让我受宠若惊啊.倒也趁此机会恶补了一下关于WebView的那些知识.恩-- 前言 现在 App 嵌入 H5 页面已经是稀 ...
- echarts一次渲染两个图_一次 Flutter WebView 性能优化
本文记录了基于 WebView 的 Flutter 可视化库:echarts_flutter 的一次优化加载性能的过程. 对于任何基于 WebView 的组件,html 的加载都是关乎性能的一个重要环 ...
- WebView性能优化--独立进程
Android允许一个app同时存在多个进程,可以根据需要把不同的模块放到不同进程中处理. 一.WebView独立进程的好处 1.有效增大App的运存,减少由webview引起的内存泄露对主进程内存的 ...
- SQL SERVER 性能优化四: 创建分区表
1.整体介绍 1.1 分区表概念:分区表值得是逻辑上是一个表,物理上被存储到不同的磁盘文件中. 1.2 优势:提高查询性能:提高稳定性:便于管理:对于大数据量表备份更方便. 1.3 建立分区表主要包含 ...
- ajax预加载html seo,前端性能优化 — JS预加载和懒加载
JS预加载 需求:有时我们需要实现例如快速快速切换页面.图片之类的功能时,能尽快的加载出我们所需的图片会极大提升用户体验,这时用预加载将图片先缓存到浏览器,用户使用需显示图片时无疑会顺畅很多. 核心: ...
- 前端性能优化之预加载
网络连接的快慢,是前端性能的瓶颈之一,在这里我们能做些什么呢,下面介绍几个通过浏览器特性来很容易提高资源加载速度的方法: DNS prefetching DNS解析的速度可用通过下面的标签来进行预解析 ...
- 前端性能优化:预渲染
预渲染 可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染 <link rel="prerender" href="http://poetries ...
最新文章
- JS break语句和continue语句
- 炒鸡简单,带你快速撸一遍Numpy代码!
- K-means算法在手写体数字图像数据上的使用示例-代码详解
- 函数指针指向类的静态成员函数
- sass之mixin的全局引入(vue3.0)
- 成本预算的四个步骤_工业企业成本管理之成本控制体系的构建
- linux常用查看磁盘空间大小的命令
- Kali下TheFatRat工具的安装教程
- xshell链接相当的慢,怎么解决
- 图片OCR进行在线的文字识别
- java实现登录注册界面
- wuauclt.exe进程和wuauclt病毒的查杀清理方法
- SQI SERVER2016安装选项
- JAVA时间字符串去空格、冒号和横杠
- Pinned Memory 多设备异步拷贝
- Python 100道基础入门练习题(附答案)【这期完结】
- CPU当中的分支预测
- jenkins 流水线参数化构建例子
- Token的简单解释
- springboot slf4j log4j2 动态创建日志的方法
热门文章
- 4种大文件传输工具和软件,用于共享大文件
- 看美国无线路由器品牌用户满意度排行榜
- 关于能连上网却打不开网页的问题
- puzzle(0711)《机关排布》接水管、搭桥
- document.forms[0].submit();和document.forms[0].action = ““;问题
- 用html做完整网页效果
- matlab上机绘图实验心得,matlab实验心得总结
- 家谱世表怎么写?4个要点不注意,会让人贻笑大方的
- SpringBoot-集成Shiro
- linux下非root用户如何修改root权限的文件