隨著Android應(yīng)用開發(fā)規(guī)模的擴大,客戶端業(yè)務(wù)邏輯也越來越復(fù)雜阱飘,已然不是簡單的數(shù)據(jù)展示了斥杜。如同后端開發(fā)遇到瓶頸時采用的組件拆分思想虱颗,客戶端也需要進行架構(gòu)設(shè)計,拆分視圖和數(shù)據(jù)蔗喂,解除模塊之間的耦合忘渔,提高模塊內(nèi)部的聚合度。
開始之前先上一張內(nèi)部分享時用的PPT圖:
以上是筆者在客戶端開發(fā)過程中面臨的問題缰儿,涉及到以下四個主題:
- Android App的架構(gòu)設(shè)計:從VM畦粮、MVC、MVP到MVVM
- Android App的網(wǎng)絡(luò)訪問:支持REST乖阵、HTTPS及SPDY的Retrofit+Okhttp
- Android App的響應(yīng)式編程:RxJava/RxAndroid解決方案
- Android App的依賴注入:Dagger2和ButterKnife使用
本文將從架構(gòu)設(shè)計入手宣赔,分享筆者在Android開發(fā)中采用MVC、MVP及MVVM的一些想法瞪浸。
一儒将、Android原生開發(fā)中的MVC
Android原生開發(fā)采用XML文件實現(xiàn)頁面布局,通過Java在Activity中開發(fā)業(yè)務(wù)邏輯默终,這種開發(fā)模式實際上已經(jīng)采用了MVC的思想椅棺,分離視圖和控制器。MVC模式(Model–view–controller)是軟件工程中的一種軟件架構(gòu)模式齐蔽,把軟件系統(tǒng)分為三個基本部分:模型(Model)两疚、視圖(View)和控制器(Controller)。
MVC模式最早由Trygve Reenskaug在1978年提出含滴,是施樂帕羅奧多研究中心(Xerox
PARC)在20世紀80年代為程序語言Smalltalk發(fā)明的一種軟件架構(gòu)诱渤。MVC模式的目的是實現(xiàn)一種動態(tài)的程序設(shè)計,使后續(xù)對程序的修改和擴展簡化谈况,并且使程序某一部分的重復(fù)利用成為可能勺美。除此之外,此模式通過對復(fù)雜度的簡化碑韵,使程序結(jié)構(gòu)更加直觀赡茸。軟件系統(tǒng)通過對自身基本部分分離的同時也賦予了各個基本部分應(yīng)有的功能。專業(yè)人員可以通過自身的專長分組:
- 控制器(Controller)- 負責(zé)轉(zhuǎn)發(fā)請求祝闻,對請求進行處理占卧。
- 視圖(View) - 界面設(shè)計人員進行圖形界面設(shè)計。
- 模型(Model) - 程序員編寫程序應(yīng)有的功能(實現(xiàn)算法等等)联喘、數(shù)據(jù)庫專家進行數(shù)據(jù)管理和數(shù)據(jù)庫設(shè)計(可以實現(xiàn)具體的功能)华蜒。
——以上內(nèi)容來自《維基百科》
在Android編程中,View對應(yīng)xml布局文件豁遭,Model對應(yīng)實體模型(網(wǎng)絡(luò)叭喜、數(shù)據(jù)庫、I/O)蓖谢,Controller對應(yīng)Activity業(yè)務(wù)邏輯捂蕴,數(shù)據(jù)處理和UI處理譬涡。如下圖所示。
但在實際開發(fā)過程中启绰,純粹作為View的各個XML文件功能較弱昂儒,Activity基本上都是View和Controller的合體,既要負責(zé)視圖的顯示又要加入控制邏輯委可,承擔(dān)的功能很多,導(dǎo)致代碼量很大腊嗡。所有更貼切的目前常規(guī)的開發(fā)說應(yīng)該是View-Model模式着倾,大部分都是通過Activity的協(xié)調(diào),連接處理邏輯的燕少。
二卡者、從MVC過渡到MVP
在業(yè)務(wù)邏輯稍微復(fù)雜一點的頁面,Activity的代碼超過一千是很容易的客们,如果作者又剛好讀過《如何寫出無法維護的代碼》崇决,那么恭喜后來接手該代碼的童鞋,接下來的幾個月會很酸爽的底挫。恒傻。。
既然Activity存在代碼量過大的問題建邓,那自然會想到進行拆分盈厘。上節(jié)說到Android原生開發(fā)采用了MVC的思想,但Activity并不是一個標(biāo)準(zhǔn)的MVC模式中的Controller官边,它的首要職責(zé)是加載應(yīng)用的布局和初始化用戶界面沸手,并接受并處理來自用戶的操作請求,進而作出響應(yīng)注簿。隨著界面及其邏輯的復(fù)雜度不斷提升契吉,Activity類的職責(zé)不斷增加,以致變得龐大臃腫诡渴。
MVP是從MVC過渡而來捐晶,MVP框架由三部分組成:View負責(zé)顯示,Presenter負責(zé)邏輯處理玩徊,Model提供數(shù)據(jù)租悄。Android開發(fā)從MVC過渡到MVP,最主要的變化就是將Activity中負責(zé)業(yè)務(wù)邏輯的代碼移到Presenter中恩袱,Activity只充當(dāng)MVP中的View泣棋,負責(zé)界面初始化以及建立界面控件與Presenter的關(guān)聯(lián)。
這樣拆分之后畔塔,Presenter承擔(dān)了大量的邏輯操作潭辈,避免了Activity的臃腫鸯屿。整個架構(gòu)如下圖所示。
- View(Activity)負責(zé)響應(yīng)用戶操作把敢,通過Presenter暴露的方法請求數(shù)據(jù)寄摆;
- Presenter在獲取數(shù)據(jù)后,通過View(Activity)暴露的方法實現(xiàn)界面控制(showLoading/showUsers)修赞;
- Presenter的數(shù)據(jù)是通過Model來獲取的婶恼,Model包含網(wǎng)絡(luò)、數(shù)據(jù)庫以及I/O等柏副;
- Model通過回調(diào)的方式將數(shù)據(jù)傳到Presenter中勾邦。
采用MVP明顯的優(yōu)點是避免了傳統(tǒng)開發(fā)模式中View和Model耦合的情況,提高了代碼可擴展性割择、組件復(fù)用能力眷篇、團隊協(xié)作的效率以及單元測試的便利性。但也有一些缺點荔泳,比如:
- Model到Presenter的數(shù)據(jù)傳遞過程需要通過回調(diào)蕉饼;
- View(Activity)需要持有Presenter的引用,同時玛歌,Presenter也需要持有View(Activity)的引用昧港,增加了控制的復(fù)雜度;
- MVC中Activity的代碼很臃腫沾鳄,轉(zhuǎn)移到MVP的Presenter中慨飘,同樣造成了Presenter在業(yè)務(wù)邏輯復(fù)雜時的代碼臃腫。
三译荞、從Presenter到ViewModel
MVVM是Model-View-ViewModel的簡稱瓤的,從實際效果來看,ViewModel是View的數(shù)據(jù)模型和Presenter的結(jié)合吞歼,具體結(jié)構(gòu)如下圖所示:
- View(視圖層)采用XML文件進行界面的描述圈膏;
- Model(模型層)通過網(wǎng)絡(luò)和本地數(shù)據(jù)庫獲取視圖層所需數(shù)據(jù);
- ViewModel(視圖-模型層)負責(zé)View和Model之間的通信篙骡,以此分離視圖和數(shù)據(jù)稽坤。
View和Model之間通過Android Data Binding技術(shù),實現(xiàn)視圖和數(shù)據(jù)的雙向綁定糯俗;ViewModel持有Model的引用尿褪,通過Model的方法請求數(shù)據(jù);獲取數(shù)據(jù)后得湘,通過Callback(回調(diào))的方式回到ViewModel中杖玲,由于ViewModel與View的雙向綁定,使得界面得以實時更新淘正。同時摆马,界面輸入的數(shù)據(jù)變化時臼闻,由于雙向綁定技術(shù),ViewModel中的數(shù)據(jù)得以實時更新囤采,提高了數(shù)據(jù)采集的效率述呐。
采用ViewModel解決MVP中View(Activity)和Presenter相互持有對方應(yīng)用的問題,界面由數(shù)據(jù)進行驅(qū)動蕉毯,響應(yīng)界面操作無需由View(Activity)傳遞乓搬,數(shù)據(jù)的變化也無需Presenter調(diào)用View(Activity)實現(xiàn),使得數(shù)據(jù)傳遞的過程更加簡潔恕刘,高效缤谎。
在Android中實現(xiàn)MVVM架構(gòu)的核心支撐技術(shù)是Google去年I/O大會開源的Data binding技術(shù),這項技術(shù)的思想并不新穎褐着,最初由微軟提出,在前端開發(fā)中已經(jīng)有成熟的應(yīng)用托呕。下面對其進行簡要的介紹含蓉。
四、Android中的Data Binding
學(xué)習(xí)Data Binding主要推薦兩個內(nèi)容:
官方的Data Binding教程
精通 Android Data Binding
這兩篇文章中已經(jīng)將Data Binding的基本內(nèi)容描述的很詳細了项郊。這里僅列兩個在實踐中遇到的坑馅扣,拋磚引玉。
- ObservableField的get方法可能無法返回界面實時更新的內(nèi)容
public ObservableField<String> username = new ObservableField<>();
上述username表示用戶名着降,在界面上可能會與EditText綁定差油。通過username的set方法可以設(shè)置EditText顯示,但如果輸入變更后任洞,通過get方法卻不一定能及時返回界面的數(shù)據(jù)蓄喇。
- Data Binding依然有很多支持的不好的組件(listview,recyclerView等)交掏,不可能通過給所有組件綁定ViewModel從而實現(xiàn)Activity沒有業(yè)務(wù)邏輯操作妆偏。另外,ViewModel獲取數(shù)據(jù)之后盅弛,也不可能把所有數(shù)據(jù)直接綁定到界面钱骂,有些也需要通過回調(diào)傳到Activity中。
從MVC挪鹏、MVP到MVVM见秽,實際上是模型和視圖的分離過程。MVC中模型和視圖沒有完全分離讨盒,造成Activity代碼臃腫解取,MVP中通過Presenter來進行中轉(zhuǎn),模型和視圖徹底分離催植,但由于V和P互相引用肮蛹,代碼不夠優(yōu)雅勺择。ViewModel通過Data Binding實現(xiàn)了視圖和數(shù)據(jù)的綁定,解決了這種MVP的缺陷伦忠,但目前也存在Data Binding還不成熟的問題省核。
其實,MVC昆码、MVP及MVVM沒有絕對好壞气忠,在軟件編程過程中,也沒必要非此即彼赋咽,最重要的是讓軟件高內(nèi)聚旧噪、低耦合、可維護脓匿、可擴展淘钟,至于架構(gòu),根據(jù)實際情況選擇吧陪毡。