本文內(nèi)容主要是轉(zhuǎn)載助隧,整理了幾篇較好的博客的內(nèi)容并村,做了一點(diǎn)總結(jié)與補(bǔ)全
3種架構(gòu)的示意圖
雖然示意圖有各種版本的,但基本上思想都是一致的哩牍,個人覺得以下這個系列比較好,只是鑒于MVC的示意圖思想有兩種不同的瓦盛,所以這里同時提出來外潜。
上面的MVC的示意圖與接下來要講的MVC示意圖有點(diǎn)差異处窥,主要是View和Model之間如何通信的問題,有說法認(rèn)為這只是MVC的兩個變種而已滔驾,不管如何哆致,在MVC中,Activity主要充當(dāng)Controller的角色(其實(shí)還負(fù)責(zé)了一部分View的角色)這一點(diǎn)是不變的摊阀,而在MVP中Activity則是充當(dāng)View的角色踪蹬。
正文
這部分《正文》的內(nèi)容轉(zhuǎn)載自:Android App的架構(gòu)設(shè)計(jì):從VM跃捣、MVC夺蛇、MVP到MVVM
隨著Android應(yīng)用開發(fā)規(guī)模的擴(kuò)大,客戶端業(yè)務(wù)邏輯也越來越復(fù)雜刁赦,已然不是簡單的數(shù)據(jù)展示了。如同后端開發(fā)遇到瓶頸時采用的組件拆分思想,客戶端也需要進(jìn)行架構(gòu)設(shè)計(jì)宦焦,拆分視圖和數(shù)據(jù)顿涣,解除模塊之間的耦合,提高模塊內(nèi)部的聚合度涛碑。
開始之前先上一張內(nèi)部分享時用的PPT圖:
以上是筆者在客戶端開發(fā)過程中面臨的問題蒲障,涉及到以下四個主題:
Android App的架構(gòu)設(shè)計(jì):從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è)計(jì)入手,分享筆者在Android開發(fā)中采用MVC坑赡、MVP及MVVM的一些想法毅否。
一、Android原生開發(fā)中的MVC
Android原生開發(fā)采用XML文件實(shí)現(xiàn)頁面布局螟加,通過Java在Activity中開發(fā)業(yè)務(wù)邏輯熊泵,這種開發(fā)模式實(shí)際上已經(jīng)采用了MVC的思想顽分,分離視圖和控制器泌射。MVC模式(Model–view–controller)是軟件工程中的一種軟件架構(gòu)模式但校,把軟件系統(tǒng)分為三個基本部分:模型(Model)读规、視圖(View)和控制器(Controller)修械。
MVC模式最早由Trygve Reenskaug在1978年提出,是施樂帕羅奧多研究中心(Xerox
PARC)在20世紀(jì)80年代為程序語言Smalltalk發(fā)明的一種軟件架構(gòu)肯污。MVC模式的目的是實(shí)現(xiàn)一種動態(tài)的程序設(shè)計(jì)蹦渣,使后續(xù)對程序的修改和擴(kuò)展簡化,并且使程序某一部分的重復(fù)利用成為可能柬唯。除此之外,此模式通過對復(fù)雜度的簡化失晴,使程序結(jié)構(gòu)更加直觀拘央。軟件系統(tǒng)通過對自身基本部分分離的同時也賦予了各個基本部分應(yīng)有的功能。專業(yè)人員可以通過自身的專長分組:
- 控制器(Controller)- 負(fù)責(zé)轉(zhuǎn)發(fā)請求胯陋,對請求進(jìn)行處理袱箱。
- 視圖(View) - 界面設(shè)計(jì)人員進(jìn)行圖形界面設(shè)計(jì)。
- 模型(Model) - 程序員編寫程序應(yīng)有的功能(實(shí)現(xiàn)算法等等)盟萨、數(shù)據(jù)庫專家進(jìn)行數(shù)據(jù)管理和數(shù)據(jù)庫設(shè)計(jì)(可以實(shí)現(xiàn)具體的功能)了讨。
——以上內(nèi)容來自《維基百科》
在Android編程中制轰,View對應(yīng)xml布局文件胞谭,Model對應(yīng)實(shí)體模型(網(wǎng)絡(luò)、數(shù)據(jù)庫调俘、I/O)旺垒,Controller對應(yīng)Activity業(yè)務(wù)邏輯,數(shù)據(jù)處理和UI處理骇钦。如下圖所示竞漾。
但在實(shí)際開發(fā)過程中,純粹作為View的各個XML文件功能較弱坦仍,Activity基本上都是View和Controller的合體叨襟,既要負(fù)責(zé)視圖的顯示又要加入控制邏輯幔荒,承擔(dān)的功能很多,導(dǎo)致代碼量很大右犹。所以更貼切的目前常規(guī)的開發(fā)說應(yīng)該是View-Model模式姚垃,大部分都是通過Activity的協(xié)調(diào),連接處理邏輯的积糯。
二看成、從MVC過渡到MVP
在業(yè)務(wù)邏輯稍微復(fù)雜一點(diǎn)的頁面,Activity的代碼超過一千是很容易的川慌,如果作者又剛好讀過《如何寫出無法維護(hù)的代碼》祠乃,那么恭喜后來接手該代碼的童鞋亮瓷,接下來的幾個月會很酸爽的贪嫂。。力崇。
既然Activity存在代碼量過大的問題亮靴,那自然會想到進(jìn)行拆分。上節(jié)說到Android原生開發(fā)采用了MVC的思想茧吊,但Activity并不是一個標(biāo)準(zhǔn)的MVC模式中的Controller,它的首要職責(zé)是加載應(yīng)用的布局和初始化用戶界面瞄桨,并接受并處理來自用戶的操作請求讶踪,進(jìn)而作出響應(yīng)。隨著界面及其邏輯的復(fù)雜度不斷提升柱查,Activity類的職責(zé)不斷增加云石,以致變得龐大臃腫。
MVP是從MVC過渡而來淋硝,MVP框架由三部分組成:View負(fù)責(zé)顯示宽菜,Presenter負(fù)責(zé)邏輯處理,Model提供數(shù)據(jù)参歹。Android開發(fā)從MVC過渡到MVP隆判,最主要的變化就是將Activity中負(fù)責(zé)業(yè)務(wù)邏輯的代碼移到Presenter中僧界,Activity只充當(dāng)MVP中的View臭挽,負(fù)責(zé)界面初始化以及建立界面控件與Presenter的關(guān)聯(lián)。
這樣拆分之后葬荷,Presenter承擔(dān)了大量的邏輯操作纽帖,避免了Activity的臃腫。整個架構(gòu)如下圖所示扒吁。
- View(Activity)負(fù)責(zé)響應(yīng)用戶操作室囊,通過Presenter暴露的方法請求數(shù)據(jù);
- Presenter在獲取數(shù)據(jù)后盼铁,通過View(Activity)暴露的方法實(shí)現(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)點(diǎn)是避免了傳統(tǒng)開發(fā)模式中View和Model耦合的情況寺晌,提高了代碼可擴(kuò)展性、組件復(fù)用能力呻征、團(tuán)隊(duì)協(xié)作的效率以及單元測試的便利性。但也有一些缺點(diǎn)沐祷,比如:
- 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的簡稱,從實(shí)際效果來看扶欣,ViewModel是View的數(shù)據(jù)模型和Presenter的結(jié)合千扶,具體結(jié)構(gòu)如下圖所示:
- View(視圖層)采用XML文件進(jìn)行界面的描述;
- Model(模型層)通過網(wǎng)絡(luò)和本地?cái)?shù)據(jù)庫獲取視圖層所需數(shù)據(jù)髓绽;
- ViewModel(視圖-模型層)負(fù)責(zé)View和Model之間的通信妆绞,以此分離視圖和數(shù)據(jù)。
View和Model之間通過Android Data Binding技術(shù)株茶,實(shí)現(xiàn)視圖和數(shù)據(jù)的雙向綁定图焰;ViewModel持有Model的引用,通過Model的方法請求數(shù)據(jù)僵闯;獲取數(shù)據(jù)后,通過Callback(回調(diào))的方式回到ViewModel中颗味,由于ViewModel與View的雙向綁定牺弹,使得界面得以實(shí)時更新。同時晶默,界面輸入的數(shù)據(jù)變化時航攒,由于雙向綁定技術(shù),ViewModel中的數(shù)據(jù)得以實(shí)時更新漠畜,提高了數(shù)據(jù)采集的效率憔狞。
采用ViewModel解決MVP中View(Activity)和Presenter相互持有對方應(yīng)用的問題,界面由數(shù)據(jù)進(jìn)行驅(qū)動瘾敢,響應(yīng)界面操作無需由View(Activity)傳遞簇抵,數(shù)據(jù)的變化也無需Presenter調(diào)用View(Activity)實(shí)現(xiàn),使得數(shù)據(jù)傳遞的過程更加簡潔碟摆,高效。
在Android中實(shí)現(xiàn)MVVM架構(gòu)的核心支撐技術(shù)是Google去年I/O大會開源的Data binding技術(shù)拓劝,這項(xiàng)技術(shù)的思想并不新穎嘉裤,最初由微軟提出屑宠,在前端開發(fā)中已經(jīng)有成熟的應(yīng)用仇让。下面對其進(jìn)行簡要的介紹躺翻。
四卫玖、Android中的Data Binding
學(xué)習(xí)Data Binding主要推薦兩個內(nèi)容:
官方的Data Binding教程
精通 Android Data Binding
這兩篇文章中已經(jīng)將Data Binding的基本內(nèi)容描述的很詳細(xì)了假瞬。這里僅列兩個在實(shí)踐中遇到的坑,拋磚引玉脱茉。
- ObservableField的get方法可能無法返回界面實(shí)時更新的內(nèi)容
public ObservableField<String> username = new ObservableField<>();
上述username表示用戶名琴许,在界面上可能會與EditText綁定。通過username的set方法可以設(shè)置EditText顯示榜田,但如果輸入變更后箭券,通過get方法卻不一定能及時返回界面的數(shù)據(jù)。
- Data Binding依然有很多支持的不好的組件(listview灸叼,recyclerView等)庆捺,不可能通過給所有組件綁定ViewModel從而實(shí)現(xiàn)Activity沒有業(yè)務(wù)邏輯操作。另外滔以,ViewModel獲取數(shù)據(jù)之后你画,也不可能把所有數(shù)據(jù)直接綁定到界面,有些也需要通過回調(diào)傳到Activity中坏匪。
從MVC适滓、MVP到MVVM,實(shí)際上是模型和視圖的分離過程罚屋。MVC中模型和視圖沒有完全分離,造成Activity代碼臃腫脾猛,MVP中通過Presenter來進(jìn)行中轉(zhuǎn),模型和視圖徹底分離喉刘,但由于V和P互相引用漆弄,代碼不夠優(yōu)雅撼唾。ViewModel通過Data Binding實(shí)現(xiàn)了視圖和數(shù)據(jù)的綁定,解決了這種MVP的缺陷倒谷,但目前也存在Data Binding還不成熟的問題渤愁。
其實(shí),MVC抖格、MVP及MVVM沒有絕對好壞雹拄,在軟件編程過程中,也沒必要非此即彼滓玖,最重要的是讓軟件高內(nèi)聚势篡、低耦合、可維護(hù)念祭、可擴(kuò)展绷蹲,至于架構(gòu)顾孽,根據(jù)實(shí)際情況選擇吧比规。
參考文獻(xiàn)
- 通俗易懂蜒什、有簡單的示例代碼疤估,但理論知識不夠深入,可以快速了解架構(gòu)的基本思想
Android App的架構(gòu)設(shè)計(jì):從VM钞瀑、MVC慷荔、MVP到MVVM
- 本文正文轉(zhuǎn)載的出處,理論知識精簡易懂贷岸,也比較深入磷雇,快速了解架構(gòu)的思想精華唯笙,但沒有示例代碼
Android App的設(shè)計(jì)架構(gòu):MVC,MVP,MVVM與架構(gòu)經(jīng)驗(yàn)談
- 理論知識也比較深入,有示例代碼崩掘,可以作為參考性實(shí)現(xiàn),但是內(nèi)容稍顯冗長