Android下MVVM-Databinding框架
引言
? ? ? ?MVVM和Databinding是當(dāng)前非常流行且實用的框架和工具,相信大家已經(jīng)對MVC同仆、MVP丢间、MVVM框架以及Databinding有一定的了解惫叛。本篇文章主要介紹一個基于Databinding封裝的MVVM框架当凡,并且結(jié)合當(dāng)下非常火的Android Architecture Components庫可以實現(xiàn)一種更簡單的MVVM框架如叼。
一冰木、MVVM-Databinding框架背景
? ? ? ?開篇先來了解下MVVM和Databinding及其各自優(yōu)勢,才能說明我們?yōu)槭裁匆晦o辛勞的合二為一,并希望最終達到1+1>2的效果踊沸。
1.? MVVM框架簡介及優(yōu)勢
? ? ? ?MVVM框架類似于早期的MVC和近期的MVP歇终,但是比起這兩個更為強勢。MVVM中的ViewModel層類似MVP的Presenter層逼龟,所需要做的完全就是跟邏輯相關(guān)的代碼评凝,完全不會涉及到UI。當(dāng)數(shù)據(jù)變化腺律,直接驅(qū)動UI的改變奕短,中間省去了MVP中冗余的接口。同時匀钧,在ViewModel層編寫代碼中翎碑,要求開發(fā)者需要將每個方法盡可能的做的功能單一,不與外部有任何的引用或者是聯(lián)系榴捡,無形中提高了代碼的健壯性杈女,方便了后期的單元測試朱浴。如果想進一步了解的話吊圾,可以看下我同事寫的文章(https://mp.weixin.qq.com/s/qk9vJcPgcVPYDn2rTTCJ1A)。下圖形象說明了MVC翰蠢、MVP项乒、MVVM的進化過程:
2.? 數(shù)據(jù)綁定框架DataBinding簡介及優(yōu)勢
? ? ? ?DataBinding是谷歌出臺的工具,可以實現(xiàn)UI和數(shù)據(jù)的綁定梁沧。我們的View和ViewModel通過DataBinding可以實現(xiàn)單向綁定或雙向綁定檀何,做到UI和數(shù)據(jù)的相互監(jiān)聽。同時開發(fā)者的任務(wù)分配也就很明確了廷支,負(fù)責(zé)ViewModel的小伙伴完全不用考慮UI如何實現(xiàn)频鉴,很大程度上提高了代碼的開發(fā)效率和后期出問題跟蹤的準(zhǔn)確性,針對這些好處恋拍,采用MVVM進行代碼開發(fā)還是非常有必要的垛孔。當(dāng)然,實現(xiàn)MVVM框架不是只能用DataBinding施敢,可以實現(xiàn)UI和數(shù)據(jù)綁定的框架都可以周荐,像開源框架RoboBinding等,甚至也可以使用Android Architecture Components庫中的Livedata實現(xiàn)手動綁定UI和數(shù)據(jù)僵娃。如果您對Databinding不太熟悉概作,可以看下我寫的這篇入門文章(http://www.reibang.com/p/9fb720f405a7)。下圖描述了Databinding數(shù)據(jù)流向:
3.? MVVM-DataBinding框架簡介
? ? ? ?谷歌提供了一個Databinding工具默怨,為什么我們要重新定義一套框架呢讯榕?其實在我們使用Databinding的過程中可以發(fā)現(xiàn),單純的使用Databinding使用有幾個痛點: 1.Databinding規(guī)則比較多匙睹,而且每個人對其理解不同瘩扼,用起來比較雜亂谆甜,導(dǎo)致代碼閱讀性差;2.對于已經(jīng)使用MVP框架的開發(fā)者來說集绰,希望進化到MVVM更順滑规辱,那要是能把Presenter改成ViewModel就能完成轉(zhuǎn)化簡直太開心了。3.實現(xiàn)Databinding數(shù)據(jù)和UI綁定的方法(如使用DatabindingUtil)較為機械且繁瑣栽燕。如今并沒有一個好的框架能規(guī)避以上問題罕袋,于是我將DataBinding工具和MVVM框架進行了封裝,希望能解決以上問題并融合兩者的優(yōu)點碍岔,最終達到1+1>2的效果浴讯,下面將講述是如何做到的。庫代碼可以移步我的github地址(https://github.com/ganlinux/JDMvvmDatabinding.git)蔼啦。
二榆纽、MVVM-Databinding框架詳解
? ? ? ?下面我將通過三部分介紹我的MVVM-Databinding框架:1.如何使用本框架2.本框架的實現(xiàn)過程。3.本框架的優(yōu)點及可能的隱患捏肢。
1奈籽、如何使用本框架
? ? ? ?通常我們開發(fā)過程中會在Activity、Fragment鸵赫、樓層衣屏、列表item中使用UI控件,所以我們的框架也將支持這幾種情況的數(shù)據(jù)綁定辩棒。俗話說“無規(guī)矩不成方圓”狼忱,我們通過定義少量規(guī)則來避免使用Databinding中的大量規(guī)則,進而提高代碼可讀性一睁。以下是我們約定的五點規(guī)則:
? ? ? ?①??? 我們約定把Activity钻弄、Fragment綁定的數(shù)據(jù)放在xxxViewModel中,樓層綁定的數(shù)據(jù)放在樓層類(代碼中的xxxFloor)中者吁,列表item綁定的數(shù)據(jù)放在ViewHolder中窘俺。就是說要綁定的數(shù)據(jù)都會放在其處理邏輯的類中。
? ? ? ?②??? Activity和Fragment的布局文件要做些改變砚偶,要綁定的數(shù)據(jù)類名稱(如xxxViewModel)使用"viewModel"批销,其類型為要綁定數(shù)據(jù)的全路徑類名。如下圖示例:
? ? ? ?③? ? 樓層的布局文件中引用的數(shù)據(jù)類使用名稱為"floor"染坯,類型也是要綁定數(shù)據(jù)的全路徑類名均芽,如下圖示例:
? ? ? ?④? ? 列表的item布局文件中引用的數(shù)據(jù)類使用名稱為"item",其類型也是要綁定數(shù)據(jù)的全路徑類名。如下圖示例:
? ? ? ?⑤? ? 數(shù)據(jù)的控制邏輯盡量寫在處理邏輯的類中单鹿,不要寫在布局文件中掀宋,寫在布局文件中會給排查問題造成困難并且造成他人閱讀代碼困難。
? ? ? ?以上是本框架制定的簡單規(guī)則,剩下的工作基本上跟接入MVP框架相似劲妙,與MVP不同的就是我們會修改相應(yīng)的布局文件達到UI和數(shù)據(jù)綁定的目的湃鹊。以下是接入框架的步驟:
? ? ? ?1)創(chuàng)建ViewModel/樓層/ViewHolder繼承自BaseViewModel/BaseFloorView/BindingViewHolder,里面可以創(chuàng)建要綁定的數(shù)據(jù)镣奋,例如下圖:
? ? ? ?2)創(chuàng)建layout文件币呵,按照之前的規(guī)則配置要綁定的數(shù)據(jù)。如指定生成的綁定類名為“DemoNormalFragmentBinding”侨颈,名稱為"viewModel",其類型為第一步的ViewModel的全路徑余赢,綁定布局和控件例如“android:text="@{viewModel.pageTitle}"”,如圖:
? ? ? ?3)創(chuàng)建Activity哈垢、Fragment并繼承BaseBindingMvvmActivity或BaseBindingMvvmFragment妻柒,繼承時需要指定綁定的ViewModel類和Binding類,這一步就完成了數(shù)據(jù)和布局UI的綁定耘分。樓層和列表item需要完成的是ViewHolder中數(shù)據(jù)和布局UI的綁定举塔。例如:
? ? ? ?完成了上面這三步,就已經(jīng)完成了布局和數(shù)據(jù)的綁定求泰,你需要做的就只是寫數(shù)據(jù)變化的邏輯了央渣,只要數(shù)據(jù)改變對應(yīng)的UI就會改變了。
? ? ? ?是不是很神奇拜秧?比MVP更簡潔吧痹屹?
2章郁、本框架的實現(xiàn)過程
? ? ? ?先來看下框架的代碼結(jié)構(gòu)枉氮,如圖:
? ? ? ?代碼一共分四部分,第一部分為公共的ViewBindingAdapter,主要功能是實現(xiàn)公共自定義控件的綁定注入暖庄。第二部分為Activity聊替、Fragment、Viewmodel相關(guān)基類培廓。第三部分為樓層相關(guān)基類惹悄。第四部分為Recyclerview列表相關(guān)基類。
? ? ? 這里以樓層框架為例肩钠,進行相關(guān)實現(xiàn)機制的講解:
? ? ? 1)創(chuàng)建布局文件泣港,生成BR文件占位資源。BR文件是Databinding編譯期間生成的价匠,跟R文件類似当纱,主要作用是當(dāng)數(shù)據(jù)改變后,可以用該標(biāo)識符通知 DataBinding踩窖,用新的數(shù)據(jù)去更新UI坡氯。這里占位的目的是在SDK中生成一個通用的名稱,在其他引用SDK的項目中引用。
? ? ? ?2)實現(xiàn)綁定Binding類并設(shè)置數(shù)據(jù)箫柳,就是這個步驟省去了開發(fā)者手動設(shè)置綁定的工作手形。其實就是調(diào)用了Databinding的通用綁定方法,這樣就不用開發(fā)者顯示的調(diào)用這個方法了悯恍。
? ? ? ?3)由于樓層就是一個Recyclerview的列表組成的库糠,可以繼承基類Adapter ,在onBindViewHolder調(diào)用show方法涮毫,并且調(diào)用excutePendingBindings()方法觸發(fā)刷新曼玩。
? ? ? ?以上是我樓層實現(xiàn)MVVM-Databinding框架的過程,如果不關(guān)心實現(xiàn)過程的開發(fā)者可以直接看下demo就可以上手了窒百。下圖是樓層demo的實現(xiàn)效果:
3黍判、本框架的優(yōu)點及可能的隱患
? ? ? ?這個框架大部分優(yōu)點其實是結(jié)合了MVVM和Databinding的優(yōu)點,如:
? ? ? ?1.減少findViewbyId造成的IO操作性能損耗篙梢,這是Databinding的一條優(yōu)點顷帖,因為Databinding在編譯期間就將控件從布局映射到在Binding類中,只是在綁定階段一次性實例化這些控件就直接可以使用渤滞,省去了findViewbyId的IO操作贬墩。
? ? ? ?2.減少頻繁線程切換,這條也是由Databinding的優(yōu)點妄呕,你可以在任何你想要的線程上進行更新陶舞,因為Databinding是在UI線程進行響應(yīng)。
? ? ? ?3.減少邏輯代碼冗余绪励、提高編碼效率肿孵,這條優(yōu)點就是本框架的優(yōu)勢所在,也是為什么要將這兩種優(yōu)秀框架集合在一塊的原因疏魏。
? ? ? ?4.削減DataBinding的混亂規(guī)則停做,這是單純的使用DataBinding體驗較差的地方,在我們的框架里可以摒棄其復(fù)雜的規(guī)則大莫。
? ? ? ?5.更簡單的單元測試蛉腌,這是MVVM框架的優(yōu)點,由于其天然的低耦合性只厘,可以使我們單元測試更簡單烙丛。
??可能的隱患:
? ? ? ?1.由于DataBinding在xml提供了豐富的操作符,但是由于Android studio天生的xml語法檢查的貧弱羔味,xml布局中的表達式邏輯錯誤河咽,不能準(zhǔn)確定位,導(dǎo)致debug難度增加介评,事實上一些BindingAdapter的錯誤在build的時候也會被提示xml錯誤库北。我在開發(fā)過程中遇到過幾次爬舰,常常需要重啟Android studio才能消除問題,這個問題只能寄希望于谷歌在其IDE上解決寒瓦。
? ? ? ?2.由于DataBinding是在預(yù)編譯時期生成一些布局和代碼情屹,這可能導(dǎo)致許多需要動態(tài)加載資源或代碼的工程(比如插件化工程)需要做些改變。當(dāng)然普通的APP開發(fā)使用這個框架是沒問題的杂腰。
? ? ? ?當(dāng)然如果你按照以上步驟改造了自己的APP垃你,可能過程中還會遇到一個問題,就是ViewModel中上下文引用的問題喂很,當(dāng)然如果能用應(yīng)用級別的context當(dāng)然最好惜颇,但是有時候我們必須用activity的context時可能就有些困難了,因為我們不推薦ViewModel持有context少辣,這樣做可能造成內(nèi)存泄漏凌摄,這時候我們可以結(jié)合Android Architecture Components來實現(xiàn)context的獲取,在我的github的工程中有兩個分支漓帅,其中mvvm-databinding-aac分支就是結(jié)合了Android Architecture Components來實現(xiàn)的锨亏。
三、結(jié)語
? ? ? ?數(shù)據(jù)綁定的應(yīng)用軟件開發(fā)是一種趨勢忙干,使用DataBinding的優(yōu)點顯而易見器予。在我們選擇框架的過程中需要考慮諸多問題,比如性能問題捐迫、使用便捷程度乾翔、單元測試、是否相互獨立等施戴。當(dāng)然還有一點很重要的就是反浓,共同開發(fā)的同事是否認(rèn)同并喜歡這種開發(fā)方式,畢竟這會影響到他們的開發(fā)流程暇韧,習(xí)慣和體驗勾习。如何說服他們認(rèn)可這種框架浓瞪,就需要你提供便捷和健壯的封裝框架懈玻,使他們很爽很開心很便捷地使用這種框架,并且能夠滿足項目代碼的可擴展性乾颁,解耦和相關(guān)獨立涂乌。做到這些,就能滿足調(diào)用者英岭,項目代碼健壯性湾盒,模塊獨立性和可擴展性的需要了。我以上講述算是拋轉(zhuǎn)引玉吧诅妹,希望能共同完善框架罚勾,共同進步毅人。
github地址:https://github.com/ganlinux/JDMvvmDatabinding.git