網易考拉Android客戶端網路模組設計
本文來自網易雲社群
作者:王魯才
客戶端開發中不可避免的需要接觸到訪問網路的需求,如何把訪問網路模組設計的更具有擴充套件性是每一個移動開發者不得不面對的事情。現在有很多主流的網路請求處理框架,如Square公司的 OkH ttp,Google推出的Volley,還有在OkHttp基礎上進行封裝的Retrofit等,這些都是非常優秀的網路處理框架。利用現有網路處理框架,比從零開始設計、開發網路請求節省很多開發時間,同時也避免了一些意想不到的問題。如果把這些框架直接拿來使用,不進行任何二次封裝,會使我們工程層次結構不清晰(資料存取、邏輯處理、UI展示),不利於擴充套件(替換成其他網路框架)。所以選擇一個合適的網路框架並進行封裝,這在開發過程中是非常必要的。
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。
網易雲 ofollow,noindex" target="_blank">免費體驗館 ,0成本體驗20+款雲產品!
更多網易研發、產品、運營經驗分享請訪問 網易雲社群 。
相關文章:
【推薦】 一招搞定簡訊驗證碼服務不穩定