前言
只要你掌握了基礎(chǔ)知識(shí),要想構(gòu)建一個(gè)完整的 Android App 并不難牌芋,但是想要寫出一個(gè)可維護(hù)的 App 就是另一回事了蚓炬,這時(shí)候就必須讓你自己的代碼足夠健壯,就需要避免把所有業(yè)務(wù)邏輯代碼都放在 Activity躺屁、Fragment肯夏,或者是創(chuàng)建多個(gè)比較小的只有單一功能的 class。
那么應(yīng)該怎么做呢犀暑?—— 使用 架構(gòu)模式驯击!MVC、MVP耐亏、MVVM徊都、...任何一種都要比沒有架構(gòu)設(shè)計(jì)的流水式代碼好得多,MVVM 是 Android 開發(fā)最好的架構(gòu)選擇之一广辰。Google 官方也非常支持和鼓勵(lì)開發(fā)者使用這一架構(gòu)模式暇矫。
本教程將為你講明白到底什么是 MVVM,雖然我也不喜歡理論择吊,但有時(shí)候在實(shí)際操作之前先了解它非常重要李根,所以請(qǐng)務(wù)必耐心看完。
Model-View-ViewModel 的意義
關(guān)注點(diǎn)分離原則是架構(gòu)的終極原則干发,并且每個(gè)設(shè)計(jì)模式都在盡其所能的實(shí)現(xiàn)這一點(diǎn)朱巨。在 MVVM 中,有 3 個(gè)固定部分有助于實(shí)現(xiàn)關(guān)注點(diǎn)分離:models
枉长,views
和 view models
。你還可以添加一個(gè) repository
琼讽,作為所有數(shù)據(jù)的單一真實(shí)數(shù)據(jù)來源 —— 后面詳細(xì)介紹必峰。
View
在 MVVM 中, View 不是指 TextView
钻蹬、RecyclerView
這一些控件吼蚁,而是 app 中負(fù)責(zé)處理用戶界面顯示和交互的一個(gè)部分,換一種說法就是问欠,View 負(fù)責(zé)執(zhí)行一切 Activity 或 Fragment 能做的操作肝匆。
這里有一個(gè)重要的概念:View 僅僅處理用戶的即時(shí)交互。什么意思呢顺献?不要把業(yè)務(wù)邏輯比如數(shù)據(jù)庫操作相關(guān)的業(yè)務(wù)放在 Activities 或 Fragments 中旗国。它只負(fù)責(zé)顯示一些東西在屏幕上(比如從 ViewModels 拿到的一些數(shù)據(jù)),執(zhí)行 Android 特定操作并將用戶交互事件(點(diǎn)擊注整、滑動(dòng)等)發(fā)送到各自的 ViewModel能曾。
ViewModel
ViewModel 就像 View 和業(yè)務(wù)邏輯之間的粘合劑度硝,它負(fù)責(zé)從 Repository 獲取數(shù)據(jù)并提供給 View。
當(dāng)你查看上面的架構(gòu)模型圖時(shí)寿冕,你可能想知道 View 如何獲取它應(yīng)該顯示的所有數(shù)據(jù)蕊程。如圖,箭頭僅指向一個(gè)方向 -> ViewModel驼唱。你可能注意到箭頭是單向的藻茂,這意味著 ViewModel 沒有任何關(guān)于哪些 View 正在使用它的線索。雖然這能減少類之間的糾纏玫恳,但是 ViewModel 還是需要告訴 View 需要顯示哪些數(shù)據(jù)辨赐。
這里的做法就是使 ViewModel 中的適當(dāng)數(shù)據(jù)可觀察,通過這樣做纽窟,當(dāng)數(shù)據(jù)更新時(shí)肖油,我們就無需直接從 ViewModel 去更新 View。View 已經(jīng)持有了 ViewModel 的引用臂港,因此它可以方便的觀察 ViewModel 公開的一些數(shù)據(jù)森枪。當(dāng)數(shù)據(jù)發(fā)生變化時(shí),所有觀察它的 View 都將收到相應(yīng)的更改通知(onChange() 被回調(diào))审孽。
上述一系列操作可以通過 LiveData 來完成县袱,LiveData 是一個(gè)方便的生命周期感知庫,用于創(chuàng)建可觀察對(duì)象佑力。它的一個(gè)優(yōu)點(diǎn)就是當(dāng) Activity 或 Fragment 已經(jīng)銷毀時(shí)式散,它就不會(huì)自動(dòng)向其發(fā)送通知了,這樣就無需我們自己去管理生命周期了打颤。
Model
Model 就是你放置所有特定業(yè)務(wù)代碼的地方暴拄,雖然從技術(shù)上講,ViewModel 和 Model 之間存在一個(gè)以 Repository 形式存在的中間步驟编饺,你可以將 Repository 中的所有內(nèi)容視為遠(yuǎn)離用戶界面的一組類乖篷。它負(fù)責(zé)從本地?cái)?shù)據(jù)庫或網(wǎng)絡(luò)中獲取數(shù)據(jù)并操作應(yīng)用中的數(shù)據(jù)。
Repository 具有本地存儲(chǔ)和服務(wù)器之間的中介這么一個(gè)特殊角色透且,你可以在此檢查是否應(yīng)該在本地緩存遠(yuǎn)程數(shù)據(jù)等撕蔼。Repository 也是 ViewModel 的單一真實(shí)數(shù)據(jù)來源。也就是說秽誊,當(dāng) ViewModel 想取一些數(shù)據(jù)鲸沮,它就從 Repository 拿,然后由 Repository 決定下一步該做什么锅论,對(duì)于 ViewModel 來說讼溺,數(shù)據(jù)可以從本地、網(wǎng)絡(luò)棍厌、緩存肾胯、…任何地方拿竖席,它并不關(guān)心這些 —— 這是 Repository 應(yīng)該處理的業(yè)務(wù)邏輯。
MVVM 組件的連接性
View 不僅觀察 ViewModel 中的數(shù)據(jù)敬肚,而且 ViewModel 還觀察 Repository 中的數(shù)據(jù)毕荐,后者又觀察來自本地?cái)?shù)據(jù)庫和遠(yuǎn)程數(shù)據(jù)源的數(shù)據(jù)。
為了全面考慮這一點(diǎn)艳馒,你可以通過以下方式考慮 Model憎亚,View,ViewModel弄慰,Repository 和其他類之間的聯(lián)系第美。
遍歷層次結(jié)構(gòu)時(shí),上層類直接引用其子級(jí)陆爽。另一方面什往,子級(jí)不持有其父級(jí)引用。子級(jí)只允許通過 LiveData 或任何其他庫觀察一些數(shù)據(jù)慌闭。
為了便于理解别威,請(qǐng)看下面的箭頭圖。我想在開始時(shí)為你省去不必要的混亂驴剔,這就是為什么那些可觀察到的箭頭沒有出現(xiàn)在介紹 MVVM 的第一個(gè)圖表中省古。
這里要提到的最后一件重要事情是你應(yīng)該始終遵守上面的參考樹圖,例如丧失,不要讓你的 ViewModel 繞過 Repository 直接從數(shù)據(jù)庫取數(shù)據(jù)豺妓!一切都有它的目的:使代碼模塊化,易于維護(hù)和閱讀等布讹。你今后讀代碼的時(shí)間永遠(yuǎn)大于寫代碼琳拭,所以代碼的可讀性要放在第一位,不要懶得去抽離和構(gòu)建代碼描验,以后的你會(huì)感謝當(dāng)初的自己的臀栈。
總結(jié)
在這篇文章中,你了解了MVVM架構(gòu)模式背后的概念挠乳,再加上你已經(jīng)掌握的基礎(chǔ)開發(fā)知識(shí),你可以使用這種模式構(gòu)建一個(gè)真正的可維護(hù)的應(yīng)用程序了姑躲,還等什么睡扬?開始行動(dòng)吧??