Android 架構(gòu)設(shè)計(jì):MVC革骨、MVP良哲、MVVM

本文內(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)

Android MVC,MVP和MVVM 思想&例子

  • 通俗易懂蜒什、有簡單的示例代碼疤估,但理論知識不夠深入,可以快速了解架構(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)容稍顯冗長
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市枉疼,隨后出現(xiàn)的幾起案子骂维,更是在濱河造成了極大的恐慌,老刑警劉巖航闺,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異懈叹,居然都是意外死亡分扎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菲饼,“玉大人肾砂,你說我怎么就攤上這事『暝茫” “怎么了镐确?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肛根。 經(jīng)常有香客問我辫塌,道長,這世上最難降的妖魔是什么派哲? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任臼氨,我火速辦了婚禮,結(jié)果婚禮上芭届,老公的妹妹穿的比我還像新娘储矩。我一直安慰自己褂乍,他們只是感情好持隧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逃片,像睡著了一般屡拨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上褥实,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天呀狼,我揣著相機(jī)與錄音,去河邊找鬼损离。 笑死哥艇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的僻澎。 我是一名探鬼主播貌踏,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼十饥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祖乳?” 一聲冷哼從身側(cè)響起逗堵,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凡资,沒想到半個月后砸捏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谬运,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隙赁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了梆暖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伞访。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轰驳,靈堂內(nèi)的尸體忽然破棺而出厚掷,到底是詐尸還是另有隱情,我是刑警寧澤级解,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布冒黑,位于F島的核電站,受9級特大地震影響勤哗,放射性物質(zhì)發(fā)生泄漏抡爹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一芒划、第九天 我趴在偏房一處隱蔽的房頂上張望冬竟。 院中可真熱鬧,春花似錦民逼、人聲如沸泵殴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笑诅。三九已至,卻和暖如春疮鲫,著一層夾襖步出監(jiān)牢的瞬間吆你,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工棚点, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留早处,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓瘫析,卻偏偏與公主長得像砌梆,于是被迫代替她去往敵國和親默责。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354