李 想 ,特日根 ,3
(1.長光衛(wèi)星技術(shù)有限公司,吉林 長春130000;2.吉林省衛(wèi)星遙感應(yīng)用技術(shù)重點(diǎn)實(shí)驗(yàn)室,吉林 長春130000;3.中國科學(xué)院長春光學(xué)精密機(jī)械與物理研究所,吉林 長春130000)
在當(dāng)今社會,移動端因其便攜性、低功耗以及無線網(wǎng)的快速接入等優(yōu)勢,使得人們與外部世界進(jìn)行網(wǎng)絡(luò)連接更加方便而舒適。 正因如此,移動端編程成為了當(dāng)下最熱門的計算機(jī)編程領(lǐng)域之一。 2019 年第二季度移動端操作系統(tǒng)市場份額表明,Android 系統(tǒng)占比77.14%,iOS系統(tǒng)占比22.83%,其余系統(tǒng)不及1%,由此可知Android在當(dāng)今手機(jī)行業(yè)起著舉足輕重的作用。隨著每一款應(yīng)用承載的功能不斷增多,其代碼管理也變得更為復(fù)雜。 對于Android 應(yīng)用開發(fā)來說,用Android Studio 編譯器生成Android 項目時,其生成的XML 文件和Activity 文件已經(jīng)對應(yīng)傳統(tǒng)MVC(Model-View-Controller)架構(gòu)模式的View層和Controller 層, 同時XML 文件不能實(shí)現(xiàn)全部布局功能,因此部分View 層內(nèi)容需交付給Activity 文件完成。Activity 文件隨著頁面和業(yè)務(wù)邏輯的不斷增加也會不斷增大,代碼間耦合度明顯提高[1-3],將對項目的升級和維護(hù)帶來障礙。 因此,對于大中型項目來說,MVC 架構(gòu)并不可取。
對于一個常規(guī)項目,其網(wǎng)絡(luò)請求必不可少,雖然官方提供了諸如HttpURLConnection 類等HTTP 請求方式,但該類在大量網(wǎng)絡(luò)請求時,其性能較差。
針對此問題,MVP(Model-View-Presenter)+Retrofit+OkHttp+RxJava 的架構(gòu)應(yīng)運(yùn)而生,該架構(gòu)能有效降低代碼耦合度,使Activity 文件的內(nèi)容更加單一,網(wǎng)絡(luò)請求和布局更新更加高效。 對于整個項目而言,整體結(jié)構(gòu)更加清晰,代碼可維護(hù)性也得到大幅度提升。
本文通過對MVP+Retrofit+OkHttp+RxJava 的研究分析,以《長光衛(wèi)星云極視》項目的登錄模塊為應(yīng)用案例,設(shè)計并驗(yàn)證Android 應(yīng)用開發(fā)中MVP 模式和Retrofit2+OkHttp3+RxJava2 的響應(yīng)式網(wǎng)絡(luò)請求框架結(jié)合的方法及可行性。
MVP 最早出現(xiàn)在IBM 公司的項目研發(fā)中,由Model 層(負(fù)責(zé)數(shù)據(jù)修改和操作的部分)、View 層(包含所有的UI組件,并負(fù)責(zé)與Presenter 層進(jìn)行所有交互操作)、Presenter層(負(fù)責(zé)所有項目的邏輯)組成[4-5]。
MVP 模式在多名開發(fā)人員協(xié)同開發(fā)及測試時體現(xiàn)出了更大的解耦性。 使用MVP 模式的優(yōu)勢包括:
(1)能將Activity/Fragment 中的任務(wù)獨(dú)立出來;
(2)能將單個復(fù)雜的多任務(wù)分割成多個簡單的任務(wù);
(3)可以分離頁面與數(shù)據(jù);
(4)促進(jìn)自動化單元測試[6]。
應(yīng)用程序中MVP 模式的順序圖如圖1 所示。 在一個常規(guī)的Android 應(yīng)用中會有兩個參與者:用戶(使用該程序的人)和數(shù)據(jù)(存儲的信息實(shí)體),以登錄操作為例:
(1)用戶點(diǎn)擊按鈕獲取驗(yàn)證碼;
(2)View 對象接收到用戶動作,并向Presenter 層發(fā)送委派動作,即執(zhí)行actionSendMessage()函數(shù);
(3)如果Presenter 層需要接口或數(shù)據(jù)庫中的數(shù)據(jù),則會向Model 層通過getMessage()函數(shù)發(fā)送一條檢索數(shù)據(jù)的消息,在這個過程中,Presenter 層與Model 層屬于觀察者與被觀察者的關(guān)系;
(4)當(dāng)Model 層獲取到數(shù)據(jù)時,Presenter 層將觀察到Model 層發(fā)送的事件,同時執(zhí)行returnSendMessage()函數(shù),向View 層發(fā)送一條消息,并將獲得的驗(yàn)證碼返回給用戶,至此完成獲取驗(yàn)證碼的一次操作。
圖1 MVP 模式的順序圖
Retrofit2+OkHttp3+RxJava2 是當(dāng)下最流行的Android網(wǎng)絡(luò)請求框架之一。 在Android6.0 之前,官方推薦用HttpClient 接口來進(jìn)行網(wǎng)絡(luò)請求,后續(xù)則更改為Java.net下的HttpUrlConnection 接口,但該方式僅支持HTTP/1.0和HTTP/1.1,不支持HTTP/2.0,也不支持多路復(fù)用。 當(dāng)遇到大量網(wǎng)絡(luò)請求時性能較差。 與HttpUrlConnection 相比,OkHttp3 底層基于Okio 開源庫,使用了比阻塞式IO效率更高的Java NIO(Non-Blocking I/O)。 Retrofit2 作為基于OkHttp 封裝的RESTful 網(wǎng)絡(luò)請求框架, 是當(dāng)前耦合度最低、功能最強(qiáng)大的網(wǎng)絡(luò)請求框架。 Retrofit2 與RxJava2結(jié)合使用時,前者把請求封裝進(jìn)Observable 對象,在新線程中執(zhí)行HTTP 請求,請求結(jié)束后切換到IO 線程中執(zhí)行用戶的后續(xù)動作??傮w來說,Retrofit2 用接口的方式進(jìn)行HTTP 網(wǎng)絡(luò)請求,并負(fù)責(zé)請求數(shù)據(jù)以及接收返回結(jié)果,OkHttp3 負(fù)責(zé)HTTP 請求的過程,RxJava2 負(fù)責(zé)異步以及多線程的切換。
OkHttp 是Square 公司的一款開源的網(wǎng)絡(luò)請求庫,使用OkHttp3 進(jìn)行網(wǎng)絡(luò)請求能提高HTTP 請求的加載速度,同時更節(jié)省帶寬。 OkHttp3 的高效性體現(xiàn)在以下三方面:
(1)允許連接同一主機(jī)的所有請求分享同一個socket;
(2)通過響應(yīng)式緩存來避免重復(fù)請求;
(3)當(dāng)服務(wù)端存在多個IP 地址時,若第一個地址連接失敗,OkHttp3 會通過嘗試備用IP 地址進(jìn)行靜默恢復(fù)[7]。
與OkHttp 相 同,Retrofit 也 出 自Square 公 司,Retrofit2可以理解為一個HTTP 網(wǎng)絡(luò)請求的適配器,它將一個HTTP請求通過Java/Kotlin 接口動態(tài)代理的方式來表達(dá),并通過OkHttp3 發(fā)送HTTP 請求。 Retrofit 和OkHttp 的關(guān)系可以總結(jié)為:OkHttp 純粹是一個HTTP/SPDY 客戶端;Retrofit 是基于HTTP 的高級REST 抽象。
Retrofit 框架的優(yōu)勢在于:
(1)使用清晰的注解方式,在最大程度上簡化URL的拼寫形式;
(2)自由度大,支持自定義Converters 及其他業(yè)務(wù)邏輯;
(3)同時支持同步執(zhí)行和異步執(zhí)行;
(4)支持多種文件解析,如GSON、JSON 和XML 等;
(5)支持RxJava。
RxJava2 是一個在JAVA 虛擬機(jī)上使用可觀測的序列組成的基于事件的異步程序庫。它可以理解為是一種觀察者模式,用觀察者和被觀察者來實(shí)現(xiàn)異步操作。 與Android 官方的異步操作方法相比,RxJava 的優(yōu)勢是簡潔,當(dāng)項目隨著迭代變得繁瑣時,RxJava 仍保持了其簡潔性[8]。
基于Retrofit2+OkHttp3+RxJava2 的響應(yīng)式網(wǎng)絡(luò)請求框架整體流程如圖2 所示。
圖2 網(wǎng)絡(luò)請求流程圖
(1)導(dǎo)入相關(guān)的依賴,將域名傳入一個Retrofit 構(gòu)造器中;
(2)通過Retrofit.create()方法傳入Java 接口并返回一個Call 對象 (該對象默認(rèn)使用OkHttp3 作為HTTP 請求的Client);
(3)RxJava2 在訂閱時調(diào)用Call.enqueue()方法來進(jìn)行HTTP 的異步請求;
(4)在網(wǎng)絡(luò)請求獲得響應(yīng)后,Call 對象對返回的信息根據(jù)設(shè)置的轉(zhuǎn)置模式進(jìn)行轉(zhuǎn)換;
(5)返回結(jié)果數(shù)據(jù)。
《長光衛(wèi)星云極視》項目采取了MVP 模式以及響應(yīng)式網(wǎng)絡(luò)框架,以獲取登錄驗(yàn)證碼為例,實(shí)現(xiàn)的目錄結(jié)構(gòu)如圖3 所示。
Model 層主要的功能是從服務(wù)端獲取數(shù)據(jù), 由LoginRepository、LoginService 和 LoginServiceimpl 組成。
(1)LoginRepository
獲取用戶驗(yàn)證碼是通過LoginRepository 類中的send-Message()方法來實(shí)現(xiàn)的,通過調(diào)用Retrofit2 的send-Message()的方法,實(shí)現(xiàn)HTTP 請求,在請求成功后,數(shù)據(jù)格式轉(zhuǎn)置為SendMessageBean 實(shí)體類對象返回,關(guān)鍵代碼如下:
圖3 項目目錄結(jié)構(gòu)圖
View 層主要對應(yīng)登錄界面LoginFragment,同時View層定義了LoginView 接口,接口中包括獲取短信成功及失敗的回調(diào)方法,LoginPresenter 通過接口returnSendMessage()和returnSendMessageError()方法與LoginFragment 進(jìn)行交互,關(guān)鍵代碼如下:
Presenter 層是View 層調(diào)用Model 層的橋梁,Login-Presenter 持有LoginView 的引用,在方法中通過用戶在LoginFragment 中觸發(fā)按鍵時,調(diào)用LoginPresenter 的對應(yīng)方法, 通過LoginService 對象進(jìn)行對Model 層的訪問,同時獲取HTTP 返回值的觀察者對象,并將值傳遞給LoginView 對 象,在LoginFragment 中 進(jìn) 行UI 更 新。 關(guān) 鍵代碼如下:
為了快速開發(fā)和提高代碼質(zhì)量, 在使用MVP+Retrofit2+OkHttp3+RxJava2 模式時,應(yīng)采取JUnit 單元測試的方式,對單個Presenter 文件和Service 文件編譯運(yùn)行。 該方式無需在真機(jī)或模擬器上全局調(diào)試,同時也無需考慮其他類文件的影響。通過JUnit 單元測試,可以快速定位到問題。
本文中通過對MVC 模式以及HTTP 網(wǎng)絡(luò)請求進(jìn)行系統(tǒng)的分析,發(fā)現(xiàn)在一個中大型項目中,采用MVC 模式,會使得充當(dāng)Controller 層的Activity/Fragment 同時充當(dāng)View 層的角色,使得文件代碼量臃腫,增加了業(yè)務(wù)邏輯的耦合度,在項目開發(fā)上乃至后期維護(hù)上都造成了很大的問題。 與此同時,當(dāng)項目進(jìn)行復(fù)雜多次的網(wǎng)絡(luò)請求場景時,官方提供的HttpURLConnection 類表現(xiàn)出了性能低下、邏輯復(fù)雜的缺陷。
根據(jù)MVP 模式的設(shè)計思想,將業(yè)務(wù)事件交付給Presenter 層進(jìn)行處理,使得Model 層和View 層做到了完全解耦,在整體項目中開發(fā)模塊職責(zé)劃分更明顯,使邏輯代碼的耦合度降低,便于后期的維護(hù)和二次開發(fā)。 與此同時基于Retrofit+OkHttp+RxJava 的響應(yīng)式網(wǎng)絡(luò)框架,在HTTP 請求上更為高效,在業(yè)務(wù)處理上相比HttpURLConnection 更簡化。 RxJava 的使用,會隨著網(wǎng)絡(luò)請求邏輯變得越來越復(fù)雜,依然保持簡潔。
本文通過上述思想設(shè)計并實(shí)現(xiàn)了《長光衛(wèi)星云極視》用戶登錄模塊,驗(yàn)證了MVP 模式與Retrofit+OkHttp+Rx-Java 的網(wǎng)絡(luò)框架在Android 應(yīng)用開發(fā)中結(jié)合的可行性,同時給出了設(shè)計思路及關(guān)鍵程序,并最終達(dá)到預(yù)期效果。