VasSonic源码解析(一)

前言

    大家都知道这个Hybird框架最近都快疯了,它旨在专注于提升页面首屏加载速度,完美支持静态直出页面和动态直出页面,兼容离线包等方案。由于加了它的官方群,也讨论了一些原理,认识了一些朋友也有这方面的需求,加上自己也要优化自己的H5页面,那么我就今天看了一下这个源码,看看人家大佬写的东西,是个啥玩意。
     个人来说,自己本没有信心来分析这种源码的,但还是今天下午硬着头皮去试了一下。如果有哪里不懂或者错误了,请大家指出,菜鸡一个,大神勿喷。
     可能需要分两次扯,本次主要讲webview初次的请求逻辑和缓存保存;下一次讲有缓存情况下,数据differ情况下的操作情况。个人感觉还有有些难上手,必须需要和后端打招呼。


代码接入

    由于个人也不知道怎么操作,那么就使用了官方引入dome,大家可以dome下载下来,看看运行试试,这里主要是从SonicTestActivity页面开始分析,主要有以下几个步骤:

//初始化Sonic引擎
SonicEngine.createInstance(new HostSonicRuntime(getApplication()),new SonicConfig.Builder().build());

//创建SonicSession
sonicSession = SonicEngine.getInstance().createSession(url,new SonicSessionConfig.Builder().build());

//绑定SonicSessionClient
sonicSession.bindClient(sonicSessionClient = new SonicSessionClientImpl());

//设置webView的VebViewClient
webView.setWebViewClient(new WebViewClient(){ 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return super.shouldInterceptRequest(view, request);
    }

     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
           Log.d("WebResource:" , "-----the url is------>>" + url);

           if (sonicSession != null) {
                return (WebResourceResponse) sonicSession.getSessionClient().requestResource(url);
           }
             return super.shouldInterceptRequest(view, url);
          }
        });

//sonicSessionClient绑定webview,webview通知sonicSessionClient绑定成功
sonicSessionClient.bindWebView(webView);
sonicSessionClient.clientReady();

    这里面涉及到很多专有名词,都是以Sonic为前缀的,比如QuickSonicSession,SonicSession,SonicRuntime,SonicUtils等等,这个不用着急,大家跟着我的思路走下去就行了,重要的地方我会标记出来的。

    上面的方法也简单说一下,初始化Sonic引擎也就是简单的搞一个SonicEngine单例,这个没什么,要用到了可以直接去看源码,但是对于创建SonicSession,这个就要自己说了:

sonicSession = SonicEngine.getInstance().createSession(url,new SonicSessionConfig.Builder().build());

    我们还是看源码吧,有些不重要的地方我删除了,大家可以自己去翻源码的:
这里写图片描述
图中已经很清楚了,先创建sessionId,这个不用多说,只需要记住每个url对应一个唯一的sessionId就行,就像我们的身份证一样,在这个框架中sessionId始终伴随着session,至于怎么生成的,大伙可以去看看makeSessionId的源码,这里就不仔细介绍了。由于我们是第一次进来,那么肯定是缓存中没有查找到,直接看internalCreateSession()方法:

这里写图片描述

当前runningSessionMap中没有当前的sessionId,所以代码进去了,当前默认的模式SonicConstants.SESSION_MODE_QUICK,这个你需要去查一下SonicSessionConfig的默认配置,这里就不多提了。现在要记得我们的sonicSession的实现是QuickSonicSession,因为有很多方法需要在QuickSonicSession中查找实现的,而SonicSession只是提供了空实现。 上图可以看出,SonicSession存在两个实现,一个是QuickSonicSession,一个是StanrdSonicSession,至于有什么不同,大家可以参考官网给出的解释,这里不做评论。
对于

 sonicSession.addCallback(sessionCallback);

sonicSession是添加回调的,这个回调没什么卵用,只是表示当前sonicSession是否在runningSessionMap中的,还是给大家看一下吧:

这个就不说了,意思还是很容易理解的。
往下看,开始进入sonicSession.start()方法:

这里写图片描述

现在来看runSoicFlow()方法,图中已经标注得很清楚了,就不说什么了。先看图,我把基本逻辑理清楚了,然后一些关键的点,就去掉了,代码如下:

这里写图片描述

先获取缓存,来看handleLocalHtml方法,在SonicSession中是空实现,如下图:
这里写图片描述

那我们去看一下它的子类吧,QuickSonicSession中的handleLocalHtml实现:
这里写图片描述

那么现在去看一下mainHandler#handleMessage()方法:
这里写图片描述

这里由于clientisReady.get()返回false,也就是说client还没准备好,那么此时就返回了,不执行下面的东西了。那么handleLocalHtml()方法就暂告一段落了。

接下来我们往下看,handleFlow_Connection()方法,这个方法比较长,还是简化一下吧,不然看得有些慌:

这里写图片描述

此时我们的htmlString为null,而responseCode是sessionConnection来自HttpUrlConnection的包装,针对不同的responseCode,有不同的处理方案,图中可以看出有handleFlow_304(),handleFlow_HttpError(),我们为了简单起见,直接去看handleFlow_firstLoad()方法,看看这里主要做了什么吧:

这里还是要看SonicSession的子类,QuickSonicSession中的handleFlow_firstLoad()方法了:

各种说明都已经写清楚了,还是一个一个去看,因为这里涉及到了很多多线程的问题,比较搞人。
这还不是很烦心的,很烦心的是另外一个东西,就是此时hasCacheData到底是true还是false。这个问题比较纠结,因为涉及到两个情况:webview先初始化完,还是网络请求先完成。这里我也不上什么代码了,我们先假设有缓存,即hasCacheData为true,那么往下走:

hasCacheData为true

显示mainHandler.sendMessage(),此时msg.what = CLIENT_CORE_MSG_FIRST_LOAD, msg.obj = htmlString,msg.arg1 = FIRST_LOAD_WITH_CACHE.其实和上面的第一次handler发送message是一样的。

因为我们的clientIsReady还是false,所以这里还是直接返回了,只不过此时的pendingClientCoreMessage被赋值了,这里需要记住,等会需要用得到。

那么什么时候clientIsReady为true呢?先看看clientIsReady是什么东西吧?

这里写图片描述

这是JDK concurrent包下的东西,简单一点就是支持原子性true Or false的操作[这个需要自己去理解吧],翻看了一下源码,发现在

sonicSessionClient.clientReady();

中有这样一段代码:
这里写图片描述

而session对应QuickSonicSession中onClientReady()方法为:

此时clientIsRead已经被设置为true,同时pendingClientCoreMessage不为空,它的值为 msg.what = CLIENT_CORE_MSG_FIRST_LOAD, msg.obj = htmlString,msg.arg1 = FIRST_LOAD_WITH_CACHE,来源于handleFlow_firstLoad()中赋值。那么此时直接查看handleMessage()方法:

此时将进入handleClientCoreMessage_FirstLoad方法中:

按照代码,现在直接回调了sessionClient.loadDataWithBaseUrlAndHeader()方法,而这个sessionClient被调用的位置是SonicSessionClientImpl中:

这里写图片描述

到了这里,我们基本上知道了Sonic是先进行了网络请求,将请求后的数据塞给了webview,而webview不是webview去进行的网络请求。大致的流程给过了一遍。好了,这是第一遍情况了,此时我们的hasCacheData为true了,下面看一下hasCacheData为false的情况.

hasCacheData为false

    这种情况怎么来呢?先听我慢慢说来,hasCacheData为false的本质是webview先初始化完毕,而网络数据后请求完成。webview初始化完成之后,开始调用

sonicSessionClient.bindWebView(webView);
sonicSessionClient.clientReady();

而clientReady方法为:

这里写图片描述

现在来看实现类QuickSonicSession中onClientReady方法:

这里写图片描述

这里又有多种情况:
1. pendingClientCoreMessage为null,状态值为state_none,那么它执行start()方法
2. pendingClientCoreMessage为null,此时session的状态值为state_run
3. pendingClientCoreMessage不为null,那么此时直接handleMessage方法【此时还区分pendingClientCoreMessage是哪一种】

其实VasSonic这个框架很多地方都考虑到了多线程,java.util.concurrent.atomic下AtomicInteger,AtomicBoolean大量被使用,这样做的好处就是在多线程条件下,数据仍然可以同步。这三种情况不可能每个都分析,那就分析一个最简单的模式pendingClientCoreMessage为null,state为state_run状态。

此时又回到sonicSession#handleLocalHtml方法中,对应实现类QuickSonicSession#handleLocalHtml中:

这里写图片描述

此时msg.what = CLIENT_CORE_MSG_PRE_LOAD, msg.arg1 = PRE_LOAD_NO_CACHE,现在来看handleMessage中方法:

此时clientIsReady已经为true了,那么直接看handleClientCoreMessage_PreLoad方法了:

此时由于msg.arg1=PRE_LOAD_NO_CACHE,那么就是需要执行 sessionClient.loadUrl(srcUrl, null);而这个方法为在sessionClientImpl方法中为:

居然最后还是叫webview去请求URL了,好了,到这里就告一段落了,基本上叫webView去请求数据了。尼玛写得这烦干嘛呢? 你这么想,那就说明你还是太low了,当初我也是这么想的,但是还有一个方法我却忽略了:

这里写图片描述

那么webView.loadUrl(url),这个url也会拦截吗?当然会了,而且还是第一个拦截的,至于为什么,大哥您自己打个log看一下吧,这里就不多说了。我们的sonicSession不为空,那么你可以去看看sonicSession.getSessionClient().requestResource(url)方法了:

这里写图片描述

那还是直接看session.onClientRequestResource方法吧,还是需要看QuickSonicSession中的实现方法:

方法中基本上都标注完成了,首先需要保证该方法只执行一次,检查网络请求是否完成,如果没有,则直接 sessionState.wait等待30s时间,所以你在源码中sonicSession#runSonicFlow方法执行的最后有这样一句话:

这里写图片描述

在网络请求完成之后,sessionState将会notify(),那么session.onClientRequestResource将会继续执行,使用

webResourceResponse = SonicEngine.getInstance().getRuntime().createWebResourceResponse(mime, "utf-8", pendingWebResourceStream, getHeaders());

那我们看看Runtime().createWebResourceResponse执行方法吧,实现类为HostSonicRuntime:

这里直接组装成了webResourceResponse对象,也就是将网络请求的数据流直接返回给了webView,其实最终结果都是一样了,都是先进行网络请求,然后把数据直接交给webview对象,而不是webview直接请求,当然了剩下的资源还是需要请求的。

总结

好了,我基本上把这个框架初次请求给过了一遍,不得不得鹅厂写的东西质量真心不错,看上去没几个类的框架里面,大量使用了多线程。对于我这种菜鸡来说,还是有一定的挑战吧。目前为止,我还只是分析了一点点初次请求的东西,还有多次请求,有缓存的情况下,后端模版变化,后端数据变化等等,所以说要彻底理解这个框架,需要一定的技术功底和时间,大家可以慢慢分析,好好学习,希望大家可以共同进步吧。有什么问题或者哪些地方不对的,大家可以指出来,毕竟菜鸡都很虚心的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值