昨天在貓眼android組內(nèi)分享了一個(gè)騰訊的VasSonic框架(加快webview首屏加載速度)。講到其中webview截?cái)嗔骱筮M(jìn)行部分加載時(shí),一個(gè)組員拋出來這么一個(gè)問題:
“既然webview可以邊讀邊解析,那么可以先給它一半的數(shù)據(jù),webview可以先渲染一部分界面,展示出來,再給它另一半的數(shù)據(jù)”。
“既然這樣的話,我們目前項(xiàng)目中webview數(shù)據(jù)加載成功后取消loading標(biāo)志
的時(shí)機(jī)是不是可以提前?因?yàn)閣ebview邊加載邊渲染,可能在全部數(shù)據(jù)加載完成之前,已經(jīng)有部分頁面加載成功了。”
回答這個(gè)問題前,我們詳細(xì)梳理下webview加載流的過程。
一般情況下,webview.load(url)后
->
從后臺(tái)獲取節(jié)點(diǎn)流inputSream
(建立連接后,注意這時(shí)候connection.getResponse()獲取inputstream節(jié)點(diǎn)流并不會(huì)阻塞,當(dāng)從inputstream節(jié)點(diǎn)流中讀取數(shù)據(jù)時(shí),即inputStream.read()一個(gè)字節(jié)一個(gè)字節(jié)讀時(shí),獲取了下一個(gè)字節(jié)后,才會(huì)返回,不然會(huì)阻塞。inputStram.read(buffer)內(nèi)部也是調(diào)用的inputStream.read())
->
webview拿到這個(gè)節(jié)點(diǎn)流后,read()這個(gè)節(jié)點(diǎn)流,讀的時(shí)候會(huì)阻塞(上面說了),邊讀邊解析這個(gè)界面。當(dāng)然你也可以把這個(gè)節(jié)點(diǎn)流全部讀到一個(gè)內(nèi)存中或緩存中,把這個(gè)內(nèi)存或緩存包成inputstream,然后再讓webview去邊讀邊解析。
VasSonic在截?cái)嗔骱筮M(jìn)行部分加載本質(zhì)上也是這個(gè)過程。webview拿到這個(gè)SonicSessionStream,和前面的一樣,從流里面read()數(shù)據(jù)邊讀邊解析。只是SonicSessionStream這個(gè)inputSream中有已經(jīng)加載好的流和未加載的節(jié)點(diǎn)流,SonicSessionStream重寫了read()方法,讀的時(shí)候先讀已經(jīng)加載好的流,再從節(jié)點(diǎn)流中讀(因?yàn)槭菑木W(wǎng)上讀,可能會(huì)阻塞)。
VasSonic在這里的優(yōu)化,并不是webview初始化好以后,把一部分?jǐn)?shù)據(jù)給webview,先進(jìn)行渲染生成畫面,再給他另外一部分?jǐn)?shù)據(jù)。而是,SonicSessionStream利用了webview的初始化的時(shí)間差來做了部分?jǐn)?shù)據(jù)加載工作。等webview初始化好以后先讀本地?cái)?shù)據(jù)再讀網(wǎng)絡(luò)節(jié)點(diǎn)的數(shù)據(jù)。這樣比等webview初始化好以后再從節(jié)點(diǎn)流中邊度邊解析要節(jié)省一點(diǎn)時(shí)間(因?yàn)閞ead()本地?cái)?shù)據(jù)時(shí)不會(huì)有阻塞)。
所以回到,昨天問的那個(gè)問題。當(dāng)webview已經(jīng)初始化好以后再讀網(wǎng)絡(luò)數(shù)據(jù),其實(shí)時(shí)間差已經(jīng)沒有了。這時(shí)候把一部分?jǐn)?shù)據(jù)給webview先渲染,再給另一部分?jǐn)?shù)據(jù)。提前去掉loading標(biāo)志這個(gè)事情能不能行得通,暫且不知道(有可能行不通,比如webview可以邊讀邊解析dom,但是渲染界面需要完整數(shù)據(jù)才可以)。但VasSonic在這里的優(yōu)化不是說的這個(gè)事情。
邊讀邊解析并不是webview獨(dú)有的特性。只要是能讀inputStream進(jìn)行解析的情況都可以叫做“邊讀邊解析”。我們從網(wǎng)絡(luò)下載一段json字符串后,json再進(jìn)行解析成model,Gson有一個(gè)方法T model= gson.frmJson(inputSteam data),可以直接接受節(jié)點(diǎn)流生成model,這就是邊讀邊解析。并不是說一定要下載好整個(gè)json string以后,我們才可以反序列化成對(duì)象。我們之前那么做,可以是為了方便緩存。不過也可能確實(shí)不知道也可以這么用,對(duì)于緩存,我們可以把節(jié)點(diǎn)流包成我們自定義的一個(gè)流,重寫流中的read()方法:在里面寫一些緩存邏輯。
所以VasSonic的這個(gè)技巧,我們也可以用在其他地方。比如打開一個(gè)視頻,我們可以在這個(gè)視頻組件或其他view初始化過程中,利用好這個(gè)時(shí)間差。將網(wǎng)絡(luò)數(shù)據(jù)的一部分先加載到本地,然后等視頻組件初始化好以后,把加載好的本地流和節(jié)點(diǎn)流組成一個(gè)SessionStream給視頻組件進(jìn)行解析。這樣視頻組件先read()本地的數(shù)據(jù),這是不會(huì)有阻塞的。讀完本地以后再度網(wǎng)絡(luò)的(可能會(huì)阻塞)。這比初始化好視頻組件以后,進(jìn)行解析的數(shù)據(jù)都是來自網(wǎng)絡(luò)節(jié)點(diǎn) 時(shí)間上要快一些(如果所有都從網(wǎng)絡(luò)節(jié)點(diǎn)上讀,可能阻塞的時(shí)間多)。