VasSonic是腾讯推出的为了提高H5页面首屏加载速度而推出的高性能Hybrid框架,目前广泛应用在QQ商城等Hybrid界面中,以提高用户体验。

https://github.com/Tencent/Va... GitHub地址

一.实现原理

几乎所有的Hybrid界面都以WebView界面为载体,H5界面加载的时间主要消耗在在WebView初始化、网络请求、WebView渲染三个部分。WebView初始化与WebView渲染均是100ms的时间量级,其中最主要的时间瓶颈在网络请求上,尤其是弱网情况下,其消耗时间将达到s级,导致H5界面白屏时间较长或无法正常打开。
为了解决这个问题,WebView中提供了
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
函数负责拦截并加载html中用到的资源文件,以此为基础,引出VasSonic的核心思想并行加载,本地缓存,模板变更。
整体的思路便是利用WebView初始化的时间并行的进行网络请求,并利用缓存进行预加载,网络请求完成后再把变化的部分返回给浏览器利用JS进行数据变更。

二.核心流程SonicSession

整个源码我们应以SonicSession文件为切入点,它管理整个并行流程,负责获取缓存,网络请求,并以向外暴露抽象方法的方式交给子类处理错误处理,预加载,模板变更,并提供与JS的唯一交互出口,下面我们具体走一遍它的流程。
当WebView启动初始化前,便会调用SonicSession的start方法,然后会在子线程调用runSonicFlow方法,开始并行处理。

在runSonicFlow中,我们会尝试获取缓存,并交由子类的handleLocalHtml进行处理,预加载就可以在这里处理。

而后会运行handleFlow_connection方法,首先他会获取SessionConnect,之后会添加本地缓存的一些信息从而获取变化后的网页,进行connect操作后,获取到responseCode,会交给SonicSession的子类进行hanldeFlow_304,handleFlow_HttpError,handleFlow_ServiceUnavailable一系列错误处理。
之后会判断缓存是否为空,缓存为空的回话会交由子类的handleFlow_FirstLoad处理,不为空的话回判断是Template变化的话会交由子类的handleFlow_TemplateChange处理,Data变化的话会交由子类的handleFlow_DataChange处理。

可见,SonicSession主要向子类在几个关键的节点上暴露方法,获取缓存后子类调用handleLocalHtml处理,网络连接结束后会根据错误码等信息交由子类的hanldeFlow_304, andleFlow_HttpError, handleFlow_ServiceUnavailable 进行一系列错误处理,获取网络请求成功后,如果缓存为空,会调用子类的handleFlowFirstLoad处理,缓存不为空的话,会根据结果的header信息判断是模板变化还是数据变化,分别交由handleFlow_TemplateChange,handleFlow_DataChange处理。

在SonicSession中,同样会提供一些方法用于各种事件的回调。
SessionClient创建完成后调用OnClientReady方法,这个方法标识着WebView已经初始化完成。
当WebView开始加载资源后,会被shouldInterceptRequest方法拦截,会调用我们的OnClientRequestResource方法,标识着WebView开始加载数据。

当WebView渲染完成,会调用OnWebReady方法,其中会携带着JS的回调方法,最后会通过setResult调用H5的回调方法。

三.两种SonicSesion的具体实现

由上面对SonicSession的分析可知,子类SonicSession所需要关注的点有
调用loadUrl或loadUrlWithBaseUrl启动浏览器加载流程。
赋值pengdingWebResourceStream,并返回给浏览器解析。
模板和Data变化通知给浏览器做相应处理。
拦截资源实现加载。
调用setResult进行浏览器回调。

1.StandardSonicSession
基于安全性上的考量,StandardSonicSession模式下仅支持loadUrl。
在浏览器准备完成后,我们就可以直接调用loadUrl,所以在OnClientReady中,我们直接就可以调用loadUrl。

关于pendingWebResourceStream的赋值,在上面一条线的流程中完成。
WebView支持边加载边渲染的特性,我们可以将流传进去后,继续进行写操作,于是定义了SonicSessionStream,之后我们会介绍到。
所以需要判断数据是否接受完成,对赋值操作做不同的处理,然后再做保存数据的操作。

下面我们看一下StandardSession的流程究竟是怎么处理的,哪些地方对pendingWebResourceStream进行了操作。

在上面的流程图中可以看到会根据模板与Data的变化进行不同的处理。
由上面的分析可知WebView在loadUrl后,可在onClientRequestResource方法中对浏览器资源的加载进行拦截,注意!这个方法内只会拦截我们的html文件,进行文件流的传入,资源文件并不会拦截。这个方法做了对网络流的等待,等待pengdingWebResourceStream有值之后,就会将流返回给浏览器进行加载渲染。
setResul在onWebReady中需吊用一次,在这里我们确定回调方法。
以后每次流程发生转变的时候需调用一次,可以帮我们明确每一次请求走的流程,更主要的是当Data变化时,我们可以调用浏览器的回调方法。

2.QuickSonicSession

与Standard核心的不同点便在于可以通过loadBaseUrl实现加在缓存的html字符串,速度上有一定优势,但安全性上有一定问题,经实测速度优势不明显。
在实现上,和Standard模式我们需要关注变化的点主要就是不能在OnClientReady中不能直接调用loadUrl,需要在有缓存的时候loadBaseUrl,然后自己构造header,其他变化不大。

四.具体流程

下面我们梳理下具体的流程,首先我们展现的是初始化的流程。

下面展现的是SonicSession start后的流程。

五.具体问题处理

不同线程间等待如何调度与通信
网络请求所在的业务在Sonic子线程中,主要通过主线程的handler与WebView所在的主线程通信。



WebView所在的主线程主要通过控制Atomic变量对子线程进行控制。


当WebView加载完成,网络请求的结果还未赋值时,将通过同步锁的方式等待网络请求的结果。

其实WebView是支持边加载边渲染的特性的,只要将数据流传递给WebView即可,于是提供了SonicSessionStream支持这种特性,下面会介绍到。

如何做网络流和内存流的桥接
可以看到网络数据完成时,直接将数据放入Stream中,而未完成时,则创建了SonicSessionStream。

其中上面的outputStream代表着已读取到内存中的memStream,responseStream则代表着仍未读取的netStream。

通过重写SonicSeesionStream的read方法即可实现桥接。

如何做局部刷新
当缓存数据网页加载完成,即调用onWebReady后,会通过javascriptInterface将js的回调方法返回给App。
当服务器想通知客户端局部刷新时,会通过头部的template-tag通知,并返回data的json。
通过比较本地的data与新data返回差异data,并将结果赋值给pendingDiffData。
然后会通过setResult调用js的回调方法,完成局部刷新过程。

缓存文件储存
进行缓存时,会计算返回结果的sha1值,并存入sp中。
获取缓存时,会从sp中读取文件的sha1值进行比对。

head管理(跨域问题)

VasSonic Android源码解析的更多相关文章

  1. android源码解析(十七)-->Activity布局加载流程

    版权声明:本文为博主原创文章,未经博主允许不得转载. 好吧,终于要开始讲讲Activity的布局加载流程了,大家都知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与andr ...

  2. Android源码解析系列

    转载请标明出处:一片枫叶的专栏 知乎上看了一篇非常不错的博文:有没有必要阅读Android源码 看完之后痛定思过,平时所学往往是知其然然不知其所以然,所以为了更好的深入Android体系,决定学习an ...

  3. Android源码解析——LruCache

    我认为在写涉及到数据结构或算法的实现类的源码解析博客时,不应该急于讲它的使用或马上展开对源码的解析,而是要先交待一下这个数据结构或算法的资料,了解它的设计,再从它的设计出发去讲如何实现,最后从实现的角 ...

  4. Android源码解析——Toast

    简介 Toast是一种向用户快速展示少量信息的视图.当它显示时,它会浮在整个应用层的上面,并且不会获取到焦点.它的设计思想是能够向用户展示些信息,但又能尽量不显得唐突.本篇我们来研读一下Toast的源 ...

  5. Android源码解析——AsyncTask

    简介 AsyncTask 在Android API 3引入,是为了使UI线程能被正确和容易地使用.它允许你在后台进行一些操作,并且把结果带到UI线程中,而不用自己去操纵Thread或Handler.它 ...

  6. Android 源码解析 之 setContentView

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41894125,本文出自:[张鸿洋的博客] 大家在平时的开发中,对于setCont ...

  7. Android源码解析——Handler、Looper与MessageQueue

    本文的目的是来分析下 Android 系统中以 Handler.Looper.MessageQueue 组成的异步消息处理机制,通过源码来了解整个消息处理流程的走向以及相关三者之间的关系 需要先了解以 ...

  8. Android 源码解析之AsyncTask

    AsyncTask相信大家都不陌生,它是为了简化异步请求.更新UI操作而诞生的.使用它不仅可以完成我们的网络耗时操作,而且还可以在完成耗时操作后直接的更新我们所需要的UI组件.这使得它在android ...

  9. 【Android源码解析】View.post()到底干了啥

    emmm,大伙都知道,子线程是不能进行 UI 操作的,或者很多场景下,一些操作需要延迟执行,这些都可以通过 Handler 来解决.但说实话,实在是太懒了,总感觉写 Handler 太麻烦了,一不小心 ...

随机推荐

  1. Windows运行(Win+R)快速启动所有程序(自定义)

    运行Win+R我们都会用,等同于开始菜单的"运行".注意,只是效果等同, 从速度来看,按win+r比用鼠标要快很多倍.用win+r启动常用程序 最常用的是输入cmd打开命令行或ca ...

  2. python3中zip()的用法

    zip函数接受任意多个可迭代对象作为参数,将对象中对应的元素打包成一个tuple,然后返回一个可迭代的zip对象. 这个可迭代对象可以使用循环的方式列出其元素 若多个可迭代对象的长度不一致,则所返回的 ...

  3. Java 类方法和类变量

    目录 一.类变量 1.如果定义类变量 2.如何访问类变量 3.类变量的使用注意事项和细节 二.类方法 1.类方法的形式 2.类方法的调用 3.类方法经典使用场景 4.类变量和类方法 三.main方法 ...

  4. tp 防止xss攻击

    跨站脚本攻击(Cross Site Scripting),攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的. ...

  5. dedeCMS自定义dede标签

    在include/taglib文件夹中新建文件hlh.lib.php,其中hlh也就是你标签的名字,function的名字也必须跟文件名对应,固定格式lib_标签名,如lib_hlh,本例子以调取文章 ...

  6. Swagger 接口文档

    目录 Swagger 介绍 Swagger 依赖 SpringBoot 集成 Swagger 配置类 常用注解 效果示例 Swagger 介绍 Swagger UI 允许任何人(无论是开发团队还是最终 ...

  7. MySQL基础_索引

    MySQL 索引(入门): 一.介绍 1.什么是索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些 ...

  8. Web网站建站过程(白嫖)——域名

    目录 1.域名注册商(选一个吧) 2.域名注册 没有域名建啥站? 1.域名注册商(选一个吧) 到时候你们就会想起: ...... 但是我们不用上面的,因为上面的太费Q,我们要用的是-- 2.域名注册 ...

  9. ES学习总结

    1.创建索引 put localhost:9200/person 2.添加数据 put  localhost:9200/person/_doc/1 { "first_name" : ...

  10. 【混合编程】C/C++调用Fortran的DLL

    [混合编程]C/C++调用Fortran的DLL 以一个简单的加法器为例,介绍C/C++调用Fortran语言DLL的操作过程 一.Fortran操作 1.1 Fortran代码 首先是加法功能的实现 ...