摘要:業(yè)務(wù)層,業(yè)務(wù)層,是最為核心的一層。對于和的狀態(tài)保存恢復(fù)也通過處理。對于的綁定操作和命令操作都是暴露的,也易于測試。需要注意的是標(biāo)簽的節(jié)點中要使用到根節(jié)點中標(biāo)簽里設(shè)置的的話需要這樣設(shè)置抽象類中設(shè)置了和注解,只起到清晰提醒作用。
前言原文發(fā)表于:Rocko"s blog(rocko.xyz)] - MVVM_Android-CleanArchitecture
"Architecture is About Intent, not Frameworks" - Robert C. Martin (Uncle Bob)
Uncle Bob 的這句話套在 MVVM 上也是適用的, MVVM 也僅僅是架構(gòu)模式(Architectural pattern),其有一套自己的理論概念(pattern)而不是規(guī)定的具體實現(xiàn)(或 Frameworks)。早之前在知乎上相關(guān)問題的回答(android UI設(shè)計MVVM設(shè)計模式討論?)中也簡單提到過 MVVM 了,M-V-X 的關(guān)系如上圖,那么這一次博主把 Fernando Cejas(android10) 的 Android-CleanArchitecture 項目中的 MVP 實現(xiàn)重構(gòu)成了用 MVVM 來實現(xiàn)。所以看這篇文章最好是先搞清了 Fernando Cejas(android10) 的 Android-CleanArchitecture sample app 和對應(yīng)的兩篇文章(見參考)。整個歷程也算比較愉快,沒什么不良反應(yīng),這篇文章理所當(dāng)然會重點說說 MVVM 的實現(xiàn)、 Data Binding 等相關(guān)的東西。那為什么擁抱 MVVM 呢。當(dāng)然是 Google 推出官方的 data binding 啦,下一次的 Android MVVM 熱潮應(yīng)該就是 data binding 放出正式版了。
分層架構(gòu)與 M-V-X首先還是先來說說 分層架構(gòu) 與 MVC or M-V-X 之間的關(guān)系。分層架構(gòu)是一種常見的軟件應(yīng)用架構(gòu),在 Java 程序中可以算是一種應(yīng)用標(biāo)準(zhǔn)了,通常又叫 N 層架構(gòu),而最常見的是 3 層架構(gòu),它包含如下 3 層:
展示層(Presentation tier),也稱為 UI 層,也就是程序的界面部分。
業(yè)務(wù)層(business logic(domain) tier), 業(yè)務(wù)層,是最為核心的一層。
持久層(Data tier),數(shù)據(jù)持久層。
3 層架構(gòu)是存在物理上分層概念的,從上往下即展示層、業(yè)務(wù)層、持久層,也從上往下由上一層依賴下一層。不同層之間也是 高內(nèi)聚低耦合 的體現(xiàn),層內(nèi)高內(nèi)聚,層間低耦合,層 是層內(nèi)具體工作的高度抽象。低耦合則是依賴倒轉(zhuǎn)原則體現(xiàn)出來,高層依賴于下層的抽象而不是具體。
接下來先說 M-V-X 的鼻祖 MVC,Model–View–Controller (MVC) is a software architectural pattern for implementing user interfaces.,所以 MVC 模式是為用戶界面設(shè)計的,在 3 層架構(gòu)中,MVC 是屬于展現(xiàn)層的部分,所以 MVVM 作為 MVC 的演進(jìn)在與分層架構(gòu)的關(guān)系上也是一樣。經(jīng)常會看到 3 層架構(gòu)與 M-V-X 混為一談的內(nèi)容,這是不正確的,雖然都是 3 部分的內(nèi)容但是不能 簡單地 把兩者的每一部分對應(yīng)起來,我們應(yīng)該理解為,在分層架構(gòu)中 M-V-X 是在展示層(Presentation tier)的應(yīng)用。這些軟件工程理論的東西就這樣了,都是大師們留下來的東西,不要隨便套上自己的概念。
Android-CleanArchitectureFernando Cejas(android10) 的 Android-CleanArchitecture 項目中也是采用典型的 3 層架構(gòu),其中 Presentation 展現(xiàn)層采用了 MVP 模式,如果還未了解過 MVP,可以看看我之前寫的文章:Android中的MVP。不過 Google 推出官方的 data binding 之后我覺得基本可以不用采用 MVP 了,在 M-V-X 中, MVP 與 MVVM 算是比較接近的了但 MVP 中的一堆 View 接口也是讓人頭疼的,而擁有 data binding 的 MVVM 則解決了這個問題,所以請大膽擁抱 MVVM。So,下面幾點是當(dāng)中除 MVVM 外涉及到的東西,MVVM 放到下一節(jié)再講。
Dagger自帶 Dagger 信仰光環(huán)者障眼之術(shù)開啟, 哈哈,你們看不到接下來的這句話了。。我現(xiàn)在也是持不贊成 di 的觀點的人(在 Android 中、、、),可以看看這場撕逼:依賴注入是否值得?。結(jié)果就是我把原項目的依賴注入模塊去掉了,對于測試中的類中的成員變量來說本來就是 Mock 抽象接口,那就直接對接口或抽象類直接 Mock 操作就可,畢竟依賴注入的解耦依然是取決于需要注入的對象的抽象,維護(hù)依賴注入模塊(Module)也是負(fù)擔(dān),測試代碼中又要多寫一套注入控制的 Dagger Module 代碼。。
RxJava、RxAndroid先說 AsyncTask,對其已經(jīng)不再想吐槽,這么重要的異步實現(xiàn),版本間(Android Api)代碼改來改去,又順序又無序、又單線程執(zhí)行又并發(fā)執(zhí)行、內(nèi)存泄露、、、。所以對于采用 RxJava 即使不采用函數(shù)響應(yīng)式編程的大概念,用它來替換 AsyncTask 和 Thread + Handler 也是推薦的。此外使用 Rx 后也不需要事件總線的框架了,對于回調(diào)監(jiān)聽直接在數(shù)據(jù)操作的 Observable 上注冊觀察者即可,相對于事件總線來說是更精準(zhǔn)的(單線)的監(jiān)聽。而事件總線的話則是更加松耦合的,出錯的話會更加難排查,這里就不再展開了。
Lambda個人、團(tuán)隊喜好,代碼簡潔了很多但是代碼的邏輯比較不好直觀理解了,原項目也只有 3 處代碼用到,故而去掉了。
此外,對于領(lǐng)域驅(qū)動設(shè)計(DDD)中 Repository,原項目中把其實現(xiàn)放到了 data 層去實現(xiàn)(接口),造成 data 層會依賴其上一層(domain 業(yè)務(wù)層),作為分層架構(gòu)個人認(rèn)為不合適所以重新把它調(diào)整了。根據(jù) DDD,個人認(rèn)為 Repository 它的存在讓領(lǐng)域?qū)樱╠omain 業(yè)務(wù))感覺不到數(shù)據(jù)訪問層的存在,它提供一個類似集合的接口提供給領(lǐng)域?qū)舆M(jìn)行領(lǐng)域?qū)ο蟮脑L問。Repository 是倉庫管理員,領(lǐng)域?qū)有枰裁礀|西只需告訴倉庫管理員,由倉庫管理員把東西拿給它,并不需要知道東西實際放在哪。
MVVM 理論簡述按照常理,先來說基本概念:
Model,domain model(領(lǐng)域模型)或是數(shù)據(jù)層代表的數(shù)據(jù)模型,也可以理解為用戶界面需要顯示數(shù)據(jù)的抽象(數(shù)據(jù))
View, 應(yīng)用的界面
ViewModel,binder 所在之處,是 View 的抽象,對外暴露出公共屬性和命令,是 View 與 Model 的(綁定)連接器
此外還有必不可少的一部分:Binder,Android 中也就是 Data binding 了,提供 View 與 Model 的綁定功能。下面是結(jié)構(gòu)圖:
Android 中實現(xiàn)目前 Android 的 data binding 還是 beta,還只是 one-way 單向綁定,功能上還有所欠缺、控制性也還不強(qiáng),但是把它寫出來還是沒問題的。對于 Activity、Fragment 而言僅僅是作為 Java View 看待,與 XML 對應(yīng),所以里面只有 View 的展現(xiàn)邏輯,此外沒有其它代碼。一個 Activity 或 Fragment(一般都 with XML) 對應(yīng)一個 ViewModel,對于一個基礎(chǔ) View(XML)可以通過繼承對應(yīng)的 ViewModel 實現(xiàn)重用,本文的代碼也有體現(xiàn)。對于 Activity 和 Fragment 的View 狀態(tài)保存恢復(fù)也通過 ViewModel 處理。因為 binding 的入口在 Activity 或 Fragment 中,所以為了方便寫個基類處理 ViewModel 和 Binding 的初始化,然后在 對應(yīng)的 XML 里加上 ViewModel 的 variable, XML 里不再有其它數(shù)據(jù)對象的 variable。
public abstract class BaseActivityextends Activity { private VM viewModel; private B binding; public void setViewModel(@NonNull VM viewModel) { this.viewModel = viewModel; } public VM getViewModel() { if (viewModel == null) { throw new NullPointerException("You should setViewModel first!"); } return viewModel; } public void setBinding(@NonNull B binding) { this.binding = binding; } public B getBinding() { if (binding == null) { throw new NullPointerException("You should setBinding first!"); } return binding; } }
ViewModel 中通過 ObservableField 來達(dá)到細(xì)粒度的控制,綁定操作都放在 ViewModel 里,然后 ViewModel 里可以有多個 domain 中的 Interator(UseCase) 來得到 View 需要渲染的數(shù)據(jù) Model。對于 ObservableField 的綁定操作和命令操作(Command)都是暴露的,也易于測試。binding 現(xiàn)在缺少手動在 Java 代碼中注冊通知事件的功能,比如有些 model 的渲染必須通過 Java 代碼來操作的話就需要了,在 Activity(Java View) 中通過向 Binding 注冊通知回調(diào),而目前只能在 XML 中知道,當(dāng)然目前也可以自己實現(xiàn),方法也有多種:接口回調(diào)、EventBus、RxBus。。
架構(gòu)圖除了 Persenter 改成 ViewModel 的邏輯、Repository 的抽象和具體都在 domain 外,其他部分基本一致,采用的測試也一致。
Clean Architecture:
MVVM_Clean-Architecture tier:
MVVM_Clean-Architecture put all:
Talk is cheap. Show you the code. ↓↓↓
MVVM_Android-CleanArchitecture
需要注意的是 include 標(biāo)簽的 XML 節(jié)點中要使用到根節(jié)點中 data 標(biāo)簽里設(shè)置的 viewModel variable 的話需要這樣設(shè)置;
抽象類 ViewModel 中設(shè)置了 @Command 和 @BindView 注解,只起到清晰提醒作用。
具體重構(gòu)更改可以查看 commit 記錄:MVVM_Android-CleanArchitecture commits??梢钥吹?Activity 和 Fragment 的代碼是很清爽的,比 MVP 更清爽,因為 View 的數(shù)據(jù)渲染操作交給 binder 去處理了。對 Activity 或其對應(yīng)界面進(jìn)行 UI 測試的話,Mock 出 model 代表的數(shù)據(jù)然后傳遞給 ViewModel 中 @BindView 暴露出的方法,然后檢驗視圖對數(shù)據(jù)的正確顯示就行了,也就是 View 對 Model 做了正確的渲染。
參考企業(yè)應(yīng)用架構(gòu)模式
Architecting Android…The clean way? (Android-CleanArchitecture 的文章,譯文略)
Architecting Android…The evolution (Android-CleanArchitecture 的文章,譯文略)
Approaching Android with MVVM
ANDROID DATABINDING: GOODBYE PRESENTER, HELLO VIEWMODEL!
本文源碼:MVVM_Android-CleanArchitecture or Rocko-Android-Demo(-MVVM_Android-CleanArchitecture)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/11716.html
閱讀 2917·2021-11-23 09:51
閱讀 1567·2021-11-15 11:36
閱讀 3026·2021-10-13 09:40
閱讀 1919·2021-09-28 09:35
閱讀 13108·2021-09-22 15:00
閱讀 1383·2019-08-29 13:56
閱讀 2937·2019-08-29 13:04
閱讀 2707·2019-08-28 18:06