網易考拉Android客戶端網絡模塊設計

本文來自網易雲社區html

做者:王魯才nginx


客戶端開發中不可避免的須要接觸到訪問網絡的需求,如何把訪問網絡模塊設計的更具備擴展性是每個移動開發者不得不面對的事情。如今有不少主流的網絡請求處理框架,如Square公司的OkHttp,Google推出的Volley,還有在OkHttp基礎上進行封裝的Retrofit等,這些都是很是優秀的網絡處理框架。利用現有網絡處理框架,比從零開始設計、開發網絡請求節省不少開發時間,同時也避免了一些意想不到的問題。若是把這些框架直接拿來使用,不進行任何二次封裝,會使咱們工程層次結構不清晰(數據存取、邏輯處理、UI展現),不利於擴展(替換成其餘網絡框架)。因此選擇一個合適的網絡框架並進行封裝,這在開發過程當中是很是必要的。django

1.   概述

   一般狀況下,客戶端數據流遵循以下圖所述方式流動,UI層負責展現數據,接收用戶操做;邏輯處理層處理用戶操做,並將處理結果反饋給UI層進行展現;數據層負責數據存取,這裏可能會涉及多種方式存取數據:本地緩存中存取數據,向服務器請求存取數據;網絡訪問層負責從服務器存取數據,數據返回後進行解析,並將結果返回給數據存取層。緩存

2.   考拉Android客戶端網絡模塊設計

下面簡要介紹一下考拉Android客戶端網絡模塊設計的變遷歷程,在這個過程當中咱們也踩了很多坑,好在咱們把這些坑都填平了,並且正在朝着更好的方向發展。服務器

在考拉項目開始之初,咱們對比了Volley、OKHttp等主流網絡處理框架,最終選擇了Volley做爲考拉Android客戶端的網絡請求模塊。Volley是在2013年IO大會上Google推出的異步網絡請求框架(和圖片加載框架),特別適合數據量小,通訊頻繁的網絡操做。網絡

2.1 存在的問題

1.      封裝擴展性差(SPDY,HTTPS);數據結構

2.      存在內存泄漏(Volley本身的問題);框架

3.      數據解析在UI線程中進行,阻塞UI展現;異步

在這一版本的網絡請求封裝中存在一個比較嚴重的問題,數據解析在UI線程中進行,在最初的幾個版本中,請求的數據量較小,UI比較簡單,阻塞UI線程的這個問題還不是特別明顯,可是隨着UI愈來愈複雜,同時請求數據、解析數據的操做也愈來愈多,阻塞UI線程解析數據,存在丟幀問題。爲了解決這個問題,引入了工做線程池,網絡請求回來之後,先將數據返回給調用者(UI線程),調用者在解析數據的時候,開啓工做線程,數據解析完成後再拋回UI線程,UI線程進行數據展現。在這個過程當中,有屢次線程切換,線程建立、切換、調度都是須要內存、時間開銷的。更要命的是,這個過程對調用者不透明,調用者必須知道當前操做是在哪一個線程中進行的。微服務

擴展性差這一點相信不少開發者都有比較痛的感悟。爲了兼容不一樣服務器返回的不一樣數據格式,在網絡請求模塊中定義了不少不一樣參數的回調方法。在請求數據時,每一種回調接口都要對應一個具體的方法(傳入的回調接口不一樣),代碼寫的比較冗餘,條理性、擴展性差,簡直要不能直視了。

2.2 重構

爲了解決上面兩個問題,對網絡請求模塊進行了重構,引入了泛型數據,從新定義了網絡數據返回結構,新增了數據解析器。根據用戶傳入的不一樣解析器,將網絡返回數據解析成不一樣類型。在網絡數據返回後,直接將數據解析操做從UI線程中拋到工做線程中,這個過程對調用者是透明的。調用者只須要知道網絡請求操做和數據解析操做是在工做線程中進行的,回調接口在UI線程中執行就能夠。

在這個網絡響應回調接口中,採用了泛型,調用者能夠返回任意數據結構,爲了提升兼容性,在錯誤回調方法中,不只傳入了錯誤碼和錯誤緣由,並且還額外增長了一個Object類型的數據,供調用者返回其餘數據信息。

KoalaStringParser是通用數據解析接口,主要針對有特殊需求的數據解析;對於通用的、與服務器約定好的數據返回格式,能夠繼承KoalaSimpleStringParser抽象類,實現onSimpleParse抽象方法解析數據。通用數據解析接口和抽象數據解析類,既保證了擴展性,又對通用數據格式有了統一處理。

2.3 數據緩存

若是不考慮數據緩存的話,上面對網絡請求的封裝基本也能知足咱們的要求了。可是若是沒有數據緩存,每次都向服務器請求數據,啓動新頁面,會有時間長短不一的加載過程,沒有網絡或者網絡很差時,會顯示一個空白頁面告訴用戶網絡不可用,這下降了用戶體驗。爲了提高用戶體驗,減小啓動頁面的等待時間,增長數據緩存是一件頗有必要的事情。緩存能夠與服務器配合,使用HTTP的緩存機制,也能夠在客戶端單獨使用。由於如今考拉服務器尚未支持緩存,現階段只能在客戶端添加緩存。

上面是在沒有服務器支持的狀況下,客戶端支持的緩存。在啓動頁面請求數據時,先判斷是否容許讀取緩存數據。容許讀取緩存數據,檢查是否存在緩存數據,存在緩存數據,將數據從本地緩存中讀取後直接返回給調用者;不存在緩存數據,不作任何處理。在檢查緩存數據時,同時向服務器發送請求,獲取數據,數據返回後更新緩存數據。這裏須要注意的是,回調接口可能會被調用兩次,一次是從緩存讀取數據的回調,一次是從服務器讀取數據的回調。出現兩次回調的問題,須要調用者進行區分,在回調方法中添加了當前回調是從本地讀取數據的回調仍是從網絡讀取數據的回調標示。

         服務端不支持緩存,只在客戶端對數據進行緩存處理,在必定程度上提高了用戶體驗,避免用戶屢次請求相同頁面時出現屢次重複加載、長時間等待的問題。這種緩存方式並不能節省用戶流量。

2.4 切換到OkHttp

前一段時間項目組提到考拉可能會引入SPDY來優化性能,後面爲了解決劫持問題,還可能會上HTTPS,考慮到OkHttp已經內置了對SPDY的支持,並且對HTTPS的封裝比較好,未雨綢繆,咱們決定從Volley轉投OkHttp了,由於以前已經對網絡請求進行了封裝,因此切換到OkHttp仍是比較容易的。

         OkHttp具備以下優勢:

1.      支持SPDY,共享同一個Socket來處理同一個服務器的全部請求;

2.      若是SPDY不可用,則經過鏈接池來減小請求延時;

3.      無縫的支持GZIP來減小數據流量;

4.      緩存網絡數據,減小重複網絡請求;

5.      支持HTTP2;

使用OkHttp既能夠在工做線程中請求數據,也能夠在UI線程中請求數據,這與Volley只能在工做線程中請求數據不一樣。在工做線程中請求數據,數據返回後不須要從新開啓線程解析數據,數據在請求線程中解析完後,直接拋到UI線程中進行展現。

3. 總結

在設計開發功能模塊時,每每爲了快速完成功能,忽略了模塊的擴展性,當後續功能愈來愈複雜時,以前設計的功能、接口已經不能知足需求時,就要從新審視模塊是否須要重構、優化,不能總在舊的代碼上打補丁,形成代碼難以閱讀、維護。

4.   SPDY簡介

SPDY是Google開發的基於傳輸控制協議(TCP)的應用層協議,用以最小化網絡延遲,提高網絡速度,優化用戶的網絡使用體驗。SPDY並非一種用於替代HTTP的協議,而是對HTTP協議的加強。新協議的功能包括數據流的多路複用、請求優先級以及HTTP報頭壓縮。SPDY協議在性能方面對HTTP作了很大的優化,語義方面並無作太大的修改。具體來講是,SPDY使用了HTTP的方法和頁眉,可是刪除了一些報頭並重寫了HTTP中管理鏈接和數據轉移格式的部分,基本上兼容HTTP。



網易雲免費體驗館,0成本體驗20+款雲產品!

更多網易研發、產品、運營經驗分享請訪問網易雲社區


相關文章:
【推薦】 上雲、微服務化和DevOps,少走彎路的辦法
【推薦】 非對稱加密與證書(上篇)
【推薦】 django項目在uwsgi+nginx上部署遇到的坑

相關文章
相關標籤/搜索