本文已經(jīng)對(duì)《第一行代碼》作者郭霖的公眾號(hào)授權(quán)獨(dú)家發(fā)布
一、什么是DataBinding?
官方文檔的描述如下:
數(shù)據(jù)綁定庫是一種支持庫,借助該庫,您可以使用聲明性格式(而非程序化地)將布局中的界面組件綁定到應(yīng)用中的數(shù)據(jù)源。
布局通常是使用調(diào)用界面框架方法的代碼在 Activity 中定義的。例如,以下代碼調(diào)用
findViewById()來查找TextView微件并將其綁定到viewModel變量的userName屬性:
TextView textView = findViewById(R.id.sample_text);
textView.setText(viewModel.getUserName());
以下示例展示了如何在布局文件中使用數(shù)據(jù)綁定庫將文本直接分配到微件。這樣就無需調(diào)用上述任何 Java 代碼。請(qǐng)注意賦值表達(dá)式中 @{} 語法的使用:
<TextView
android:text="@{viewmodel.userName}" />
借助布局文件中的綁定組件,您可以移除 Activity 中的許多界面框架調(diào)用,使其維護(hù)起來更簡單、方便。
還可以提高應(yīng)用性能,并且有助于防止內(nèi)存泄漏以及避免發(fā)生 Null 指針異常。
-
目前在網(wǎng)絡(luò)上聽到過的質(zhì)疑聲主要有兩點(diǎn):
- 使用數(shù)據(jù)綁定會(huì)影響應(yīng)用性能。
- 數(shù)據(jù)綁定寫在布局里面維護(hù)起來會(huì)很困難。
針對(duì)以上兩點(diǎn),從上面的引用中可以看出,官方明確說了是可以提高應(yīng)用的性能,并且會(huì)使項(xiàng)目維護(hù)起來更方便。
-
為什么會(huì)有人提出以上質(zhì)疑呢?
他們的觀點(diǎn)大抵可以分為以下兩種:- 數(shù)據(jù)綁定會(huì)生成額外的類進(jìn)行布局和數(shù)據(jù)的綁定
- 數(shù)據(jù)綁定會(huì)維護(hù)一個(gè)綁定數(shù)據(jù)表
DataBinderMapperImpl
其實(shí)從源碼和實(shí)現(xiàn)原理上分析,上面的質(zhì)疑好像并沒有什么問題,但是仔細(xì)一想,針對(duì)第一點(diǎn),其實(shí)沒有數(shù)據(jù)綁定生成額外的類來進(jìn)行數(shù)據(jù)綁定,我們自己不是也得寫代碼進(jìn)行類似
findViewById()然后賦值等操作么?可以理解為這里只是運(yùn)用了面向?qū)ο蟮膯我宦氊?zé)原則進(jìn)行了很好的封裝。第二點(diǎn)就更神奇了,這個(gè)數(shù)據(jù)綁定表本身就是為了提高效率而設(shè)計(jì)的,用這一丁點(diǎn)的內(nèi)存(這是一個(gè)
SparseIntArray而已,size是布局?jǐn)?shù)量),難道會(huì)比平時(shí)我們多用一張沒有壓縮過的圖片消耗大嗎?這點(diǎn)內(nèi)存而帶來的效率提高難道不值得嗎?補(bǔ)充一點(diǎn),如果因?yàn)樗^的應(yīng)用的效率而拒絕使用可以提高開發(fā)效率的技術(shù),那為什么我們不去用純
C寫呢?native的效率不是更高么?其實(shí)我們都知道,對(duì)于大多是應(yīng)用來說,和游戲或者其他高內(nèi)存消耗的應(yīng)用相比,電商類或者工具類的應(yīng)用對(duì)內(nèi)存的消耗是很小的,在技術(shù)的取舍上要分得清主次。
二、哪些情況下我可以或者應(yīng)該用DataBinding?
在使用數(shù)據(jù)綁定之前你要清楚你要拿它來解決什么問題?
-
如果只是為了替代
findViewById()那你可以去使用最新抽取出來的視圖綁定(ViewBinding)因?yàn)檫@個(gè)相對(duì)于數(shù)據(jù)綁定來說更輕巧,在DataBinding剛出來的時(shí)候并沒有單獨(dú)區(qū)分?jǐn)?shù)據(jù) or 視圖綁定,這是在新的版本中,為了更好的設(shè)計(jì),將ViewBinding進(jìn)行了單獨(dú)的抽取。
從最新版本的代碼可以看出:public abstract class ViewDataBinding extends BaseObservable implements ViewBinding {}抽象類
ViewDataBinding實(shí)現(xiàn)了ViewBinding接口,這個(gè)名字也是取得恰到好處,View-Data-Binding,其實(shí)大家常說的DataBinding是包含ViewBinding的。
說句題外話,如果只是為了替代findViewById(),并且是使用kotlin開發(fā)的話,也可以考慮Kotlin-android-extension,KAE具有和ViewBinding差不多的功能,具體使用方式在此也不介紹了,有興趣的可以去找相關(guān)資料。` -
為了實(shí)現(xiàn)數(shù)據(jù)綁定,類似數(shù)據(jù)驅(qū)動(dòng)架構(gòu),
MVVM架構(gòu)等。恭喜你,這時(shí)候Databinding是不錯(cuò)的選擇。
說到這里又涉及到MVC,MVP,MVVM設(shè)計(jì)架構(gòu)的區(qū)別,相信大家對(duì)這幾個(gè)概念都有所了解。
首先,明確一點(diǎn),架構(gòu)的目的就是為了提高開發(fā)效率,降低維護(hù)成本。
利用面向?qū)ο蟮脑O(shè)計(jì)原則,對(duì)每個(gè)模塊的職責(zé)進(jìn)行合理的劃分,為了讓其他人更好的理解架構(gòu)設(shè)計(jì)思想,然后給予每個(gè)模塊一個(gè)通用的名詞解釋,為了更好的說清楚數(shù)據(jù)綁定,這里就簡單解釋一下目前常見的幾種架構(gòu)(以Android為例)。-
MVC:- 模型層(
Model),負(fù)責(zé)處理數(shù)據(jù)邏輯,一般包含數(shù)據(jù)庫、本地?cái)?shù)據(jù)、網(wǎng)絡(luò)獲取的Bean等組成。 - 視圖層(
View),負(fù)責(zé)處理視圖顯示,一般由XML布局承擔(dān)此責(zé)任,基本組件和自定義View等充當(dāng)視圖層的補(bǔ)充元素。 - 控制層(
Control),負(fù)責(zé)處理業(yè)務(wù)邏輯,一般由Activity、Fragment承擔(dān)此責(zé)任。
- 模型層(
-
MVP:- 模型層(
Model),負(fù)責(zé)處理數(shù)據(jù)邏輯,一般包含數(shù)據(jù)庫、本地?cái)?shù)據(jù)、網(wǎng)絡(luò)獲取的Bean等組成。 - 視圖層(
View),負(fù)責(zé)處理視圖顯示,一般由XML布局承擔(dān)此責(zé)任,基本組件和自定義View等充當(dāng)視圖層的補(bǔ)充元素,Activity、Fragment充當(dāng)視圖層和控制層的粘合劑。 - ??(
Presenter),負(fù)責(zé)處理業(yè)務(wù)邏輯,由從原來MVC控制層中抽取出來的Presenter充當(dāng)控制層(Presenter)。
- 模型層(
-
MVVM:- 模型層(
Model),負(fù)責(zé)處理數(shù)據(jù)邏輯,一般包含數(shù)據(jù)庫、本地?cái)?shù)據(jù)、網(wǎng)絡(luò)獲取的Bean、(這里我單獨(dú)抽取的視圖數(shù)據(jù)ViewData概念也屬于Model層)等組成。 - 視圖層(
View),負(fù)責(zé)處理視圖顯示,一般由XML布局承擔(dān)此責(zé)任,基本組件和自定義View等充當(dāng)視圖層的補(bǔ)充元素,Activity、Fragment主要負(fù)責(zé)視圖層綁定事件觸發(fā),熟練的話也可以直接在XML中綁定觸發(fā)事件。 - ??(
ViewModel),通過數(shù)據(jù)綁定連接View和Model(這里由ViewData充當(dāng)視圖模型被綁定到視圖上)實(shí)現(xiàn)視圖層和模型層的解藕,事件觸發(fā)后通過ViewModel處理業(yè)務(wù)邏輯,并且通過數(shù)據(jù)驅(qū)動(dòng)的方式修改視圖數(shù)據(jù),而達(dá)到間接修改視圖的功能。注意:ViewModel一定不能持有視圖層的引用,同樣不能持有Context的引用!不然還是MVP!
- 模型層(
對(duì)于新手來說,看完上面說明,更讓人覺得摸不著頭腦,只是換一個(gè)名字而已,最終不還是分三層嗎?視圖層(
View)、數(shù)據(jù)層(Model)、邏輯處理層(???),這么簡單的東西,為什么搞得很高深莫測的樣子?參考一下圖示也許你就豁然開朗了:
image
其實(shí)不同的設(shè)計(jì)架構(gòu)最終目的還是為了解耦,實(shí)現(xiàn)高內(nèi)聚低耦合一直是架構(gòu)師的理想,這種情況下,每個(gè)程序員只需要關(guān)心自己的模塊就可以了。- 就拿
MVVM來說,當(dāng)一個(gè)項(xiàng)目足夠大的時(shí)候,可能有的人負(fù)責(zé)界面繪制(XML),有的人負(fù)責(zé)業(yè)務(wù)邏輯處理(ViewModel),有的人負(fù)責(zé)數(shù)據(jù)邏輯處理(Model)。這時(shí)候,每個(gè)模塊的人只需要關(guān)心自己的邏輯就可以了,而且每個(gè)模塊都可以單獨(dú)跑Use Case,每個(gè)模塊并沒有很強(qiáng)的依賴關(guān)系,而且當(dāng)某個(gè)模塊的邏輯變更了并不一定會(huì)影響到其他模塊的變更。
-
有幾點(diǎn)要注意:
1、官方的ViewModel庫并不是實(shí)現(xiàn)MVVM架構(gòu)的必備,MVVM的重點(diǎn)是解藕,通過一定方式解除View和Model的耦合,比如使用數(shù)據(jù)綁定庫DataBinding。
2、也有不使用DataBinding實(shí)現(xiàn)的MVVM嗎?其實(shí)也有,比如說郭神第三版的《第一行代碼》中的方式,利用LiveData實(shí)現(xiàn)View和Model的解藕,且ViewModel不依賴View和Context,這里郭神把Activity和Fragment當(dāng)作View的主體,而我更傾向于把XML當(dāng)作View的主體,所見即所得,看得到的當(dāng)成View,會(huì)更直觀一點(diǎn)。Activity和Fragment只是當(dāng)作一個(gè)粘合劑,比如進(jìn)行事件綁定和一些復(fù)雜動(dòng)畫的處理等。所以DataBinding更多的是服務(wù)于XML這種View的。
3、ViewModel庫是在DadaBinding庫之后才有的,ViewModel類旨在以注重生命周期的方式存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)。ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存,這樣可以更好的提升用戶體驗(yàn)和提高應(yīng)用性能。

上圖說明了
Activity經(jīng)歷屏幕旋轉(zhuǎn)而后結(jié)束的過程中所處的各種生命周期狀態(tài)。該圖還在關(guān)聯(lián)的 Activity生命周期的旁邊顯示了ViewModel的生命周期。此圖表說明了 Activity 的各種狀態(tài)。這些基本狀態(tài)同樣適用于 Fragment 的生命周期。4、其實(shí)可以從官方的介紹中看出來,官方的ViewModel庫和我們所說的MVVM架構(gòu)中的ViewModel層并不是等價(jià)的東西,ViewModel層不止包含ViewModel數(shù)據(jù)(我更愿意稱為ViewData),還應(yīng)該包含視圖模型的邏輯處理。
總的來說,為了提高開發(fā)效率,為了更好的在大型團(tuán)隊(duì)中協(xié)調(diào)開發(fā),MVVM是一個(gè)不錯(cuò)的選擇!目前為止,個(gè)人認(rèn)為DataBinding、ViewModel,再加上LiveData,是搭建MVVM架構(gòu)最完美的組合。
三、DataBinding的基本使用方式
-
第一步:要將應(yīng)用配置為使用數(shù)據(jù)綁定,請(qǐng)?jiān)趹?yīng)用模塊的 build.gradle 文件中添加 dataBinding 元素,如以下示例所示:
android { ... dataBinding { enabled = true } }
注意:即使應(yīng)用模塊不直接使用數(shù)據(jù)綁定,也必須為依賴于使用數(shù)據(jù)綁定的庫的應(yīng)用模塊配置數(shù)據(jù)綁定。
-
第二步:修改原來的XML布局文件,在原布局外層包裹一層
layout標(biāo)簽,并且使用data和variable標(biāo)簽,添加需要綁定的數(shù)據(jù),如下所示:<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data calss="MainBinding"> <variable name="user" type="com.example.User"/> </data> <!-- 原布局開始--> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName, default=default_value}"/> </LinearLayout> <!-- 原布局結(jié)束--> </layout> -
第三步:設(shè)置布局頁面以及綁定數(shù)據(jù)到頁面
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); User user = new User("Test", "User"); binding.setUser(user); }
目前為止,布局已經(jīng)和數(shù)據(jù)進(jìn)行了綁定,其實(shí)這時(shí)候和平時(shí)我們使用findViewById()然后再setText()差別并不大,精彩的是后面。
四、DataBinding的高級(jí)用法
上面雖然實(shí)現(xiàn)了基本的數(shù)據(jù)綁定,但是改變?cè)瓉淼臄?shù)據(jù)對(duì)象,界面并不會(huì)發(fā)生改變,這個(gè)時(shí)候就需要引入一個(gè)新的概念,可觀察字段
可觀察性是指一個(gè)對(duì)象將其數(shù)據(jù)變化通知給其他對(duì)象的能力。通過數(shù)據(jù)綁定庫,您可以讓對(duì)象、字段或集合變?yōu)榭捎^察。
通過數(shù)據(jù)綁定,數(shù)據(jù)對(duì)象可在其數(shù)據(jù)發(fā)生更改時(shí)通知其他對(duì)象,即監(jiān)聽器。可觀察類有三種不同類型:對(duì)象、字段和集合
當(dāng)其中一個(gè)可觀察數(shù)據(jù)對(duì)象綁定到界面并且該數(shù)據(jù)對(duì)象的屬性發(fā)生更改時(shí),界面會(huì)自動(dòng)更新。
最早的時(shí)候使用
ObservableField或者對(duì)基本數(shù)據(jù)類型封裝好的ObservableField,比如ObservableBoolean、ObservableByte
、ObservableChar、ObservableInt等,更輕量級(jí)的還有自己通過調(diào)用notifyPropertyChanged控制數(shù)據(jù)刷新。后來
LiveData的出現(xiàn),可以使用LiveData代替ObservableField并獲得更好的生命周期管理。因此這里主要講講使用LiveData實(shí)現(xiàn)Model和View的解藕。-
目前這些方式都是支持的,從代碼中可以看出,最終都會(huì)通過注冊(cè),并統(tǒng)一由
mLocalFieldObservers進(jìn)行管理。
ObservableFieldprotected boolean updateRegistration(int localFieldId, Observable observable) { return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); }LiveData調(diào)用差不多:
protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) { mInLiveDataRegisterObserver = true; try { return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER); } finally { mInLiveDataRegisterObserver = false; } }最終都調(diào)用到同樣的一個(gè)函數(shù):
protected void registerTo(int localFieldId, Object observable, CreateWeakListener listenerCreator) { if (observable == null) { return; } WeakListener listener = mLocalFieldObservers[localFieldId]; if (listener == null) { listener = listenerCreator.create(this, localFieldId); mLocalFieldObservers[localFieldId] = listener; if (mLifecycleOwner != null) { listener.setLifecycleOwner(mLifecycleOwner); } } listener.setTarget(observable); }
其實(shí)說白了就是觀察這模式的靈活運(yùn)用,最終實(shí)現(xiàn)了數(shù)據(jù)的綁定,對(duì)于雙向綁定也沒有什么特別的,自動(dòng)生成的代碼會(huì)根據(jù)我們?cè)诓季种惺欠裨O(shè)定了雙向綁定,而主動(dòng)幫我們?cè)O(shè)置一個(gè)InverseBindingListener監(jiān)聽,XML中格式如下:android:text="@={...}"。
小知識(shí)點(diǎn)
可以在
XML中使用default(默認(rèn)值)也可以不用。可以在
data標(biāo)簽中,通過class屬性指定要生成的DataBinding文件名字。可以在
data標(biāo)簽中,通過import標(biāo)簽導(dǎo)入需要使用的類類型。-
Null 合并運(yùn)算符
android:text="@{user.displayName ?? user.lastName}"這在功能上等效于:
android:text="@{user.displayName != null ? user.displayName : user.lastName}" 要使
XML不含語法錯(cuò)誤,您必須轉(zhuǎn)義<字符。例如:不要寫成List<String>形式,而是必須寫成List<String>。-
BindingAdapter、InverseBindingAdapter等注解的使用
例如設(shè)置一個(gè)斜體綁定適配器:@BindingAdapter({"strike"}) public static void setStrike(TextView view, boolean strike) { if (strike) { view.setPaintFlags(view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); } else { view.setPaintFlags(view.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG)); } }在布局中使用
<TextView ... bind:strike="@{true}" ... /> -
設(shè)置事件監(jiān)聽
<!-- 在data標(biāo)簽添加監(jiān)聽器綁定--> <variable name="onClickListener" type="android.view.View.OnClickListener" /> <!-- 在需要綁定點(diǎn)擊事件的控件上添加綁定--> ... <View android:onClick="@{onClickListener::onClick}"/> ...
五、優(yōu)雅的使用DataBinding實(shí)現(xiàn)MVVM
通過對(duì)源碼的分析可以得知,無論是使用
ObservableField還是使用LivaData最終都會(huì)在本地屬性觀察者mLocalFieldObservers中注冊(cè)監(jiān)聽,其實(shí)數(shù)據(jù)綁定庫的使用非常的靈活,除了在上面提到的使用方式,還有更多的使用方式,甚至可以在布局XML中進(jìn)行邏輯判斷,事件綁定,布局管理器設(shè)定,列表子布局設(shè)定等,可以說是無所不能。其實(shí)正是這種靈活,也遭受了很多使用者的詬病,說很多邏輯寫在XML中,調(diào)試?yán)щy,維護(hù)麻煩,更有甚者,跳出來直接得出DataBinding不能用的結(jié)論,這就好比說菜刀能傷人就說菜刀不好一樣。
有問題的不是工具,而是使用工具的方式!
-
為了給DataBinding正名,因此總結(jié)一些使用原則,分享如下。
- 原則一:能不用可觀察變量盡量不要用。
- 原則二:多個(gè)變量會(huì)同時(shí)改變的情況盡量使用一個(gè)可觀察變量進(jìn)行包裝。
-
原則三:
data標(biāo)簽?zāi)苌賹?dǎo)入一個(gè)變量盡量少導(dǎo)入。 - 原則四:XML布局盡量少或者不使用過多的邏輯判斷。
-
原則五:避免對(duì)一個(gè)數(shù)據(jù)進(jìn)行多次綁定(有人通過這種方式刷新界面,這個(gè)其實(shí)和
DataBinding的初衷違背了)。 - 原則六:嚴(yán)格遵守上述五條。
-
基于以上六條使用原則,目前經(jīng)過多次迭代,總結(jié)出了滿足絕大多數(shù)場景的
MVVM。-
第一步
整個(gè)XML使用統(tǒng)一的格式,無論是普通的布局,還是列表的Item布局,抑或是include的布局,都是使用同樣的方式,這樣就可以使用AndroidStudio的File Templates模版功能創(chuàng)建布局文件了。<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <!-- 用于控制顯示隱藏導(dǎo)入此類--> <import type="android.view.View" /> <!-- 用于點(diǎn)擊事件綁定--> <variable name="onClickListener" type="android.view.View.OnClickListener" /> <!-- 用于視圖數(shù)據(jù)綁定--> <variable name="viewData" type="com.example.UserViewData"/> </data> <!-- 原布局開始--> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/helloSomeOne" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{onClickListener::onClick}" android:text="@{viewData.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{viewData.noLastName?View.GONE:View.VISIBLE}" android:text="@{viewData.lastName, default=default_value}"/> <!-- 包含另一個(gè)布局 并傳遞事件綁定和視圖數(shù)據(jù)綁定--> <include android:id="@+id/includeViewId" layout="@layout/include_view_layout" bind:onClickListener="@{onClickListener}" bind:viewData="@{viewData}" /> </LinearLayout> <!-- 原布局結(jié)束--> </layout> -
第二步
創(chuàng)建BaseBindActivity和BaseBindFragment,實(shí)現(xiàn)底層的數(shù)據(jù)綁定,以及生命周期設(shè)定,以及事件綁定。public abstract class BaseBindActivity<B extends ViewDataBinding> extends Activity implements View.OnClickListener { private B mBinding; /** * 數(shù)據(jù)綁定 */ protected abstract <ViewData> ViewData getViewData(); /** * 子類提供有binding的資源ID */ @LayoutRes protected abstract int getLayoutID(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, getLayoutID()); if (mBinding != null) { mBinding.setLifecycleOwner(this); mBinding.setVariable(BR.onClickListener, this); mBinding.setVariable(BR.viewData, getViewData()); } else { setContentView(getLayoutID()); } } @Override public B getBinding() { return mBinding; } }這樣子頁面只需要實(shí)現(xiàn)簡單的邏輯處理就可以了。
BaseBindFragment邏輯類似就不貼代碼了。 -
第三步
在具體業(yè)務(wù)Activity中通過ViewModelProviders獲取ViewModel,并從ViewModel中獲取ViewData,將ViewData綁定到視圖中,子類通過實(shí)現(xiàn)getViewData(),進(jìn)行綁定操作。ViewModelProviders.of(this, factory).get(viewModelClass) 第四步
當(dāng)用戶操作(比如點(diǎn)擊)導(dǎo)致一個(gè)事件產(chǎn)生,在具體業(yè)務(wù)Activity中,通過ViewModel的方法調(diào)用業(yè)務(wù)數(shù)據(jù)提供方,并實(shí)現(xiàn)業(yè)務(wù)邏輯,業(yè)務(wù)處理完成后,操作ViewData中的屬性,實(shí)現(xiàn)動(dòng)態(tài)更新界面的功能。
-
很多邏輯具有通用性,我們可以抽取很多模版代碼作為基類使用,比如說列表的ListAdapter、數(shù)據(jù)庫Room、數(shù)據(jù)差分類DiffUtil.ItemCallback、RecyclerView的ViewHolder都可以進(jìn)行很好的封裝,使用時(shí)就會(huì)變得很簡單,以后再也不用處理那么多的Adapter和ViewHolder了。
因?yàn)槠?,這里就不詳細(xì)介紹了,有興趣的可以參考github源碼,源碼里面的README也有一部分介紹。
源碼傳送門
GitHub地址:https://github.com/codyer/component
說明
因?yàn)?code>component是實(shí)際開發(fā)時(shí)可能會(huì)使用到的一些組件,為了方便,我之前放在一個(gè)項(xiàng)目下統(tǒng)一管理的,因此這個(gè)項(xiàng)目包含很多模塊,感興趣的歡迎Star和Fork
如果只想看MVVM的代碼可以只參考以上項(xiàng)目的一個(gè)modlue
MVVM-模塊
GitHub地址:https://github.com/codyer/component/blob/master/app-core/README.md
至此,為DataBinding的正名就算完成了。
尾記
寫這篇文章花了整整一天的時(shí)間,希望走過路過的伙伴們不要吝嗇一個(gè)點(diǎn)贊和Star。
另外,之前因?yàn)闄C(jī)緣巧合實(shí)現(xiàn)了一套基于LiveData的事件總線LiveEventBus,自己使用下來發(fā)現(xiàn)其實(shí)還是很不錯(cuò)的,之前一直做項(xiàng)目也不空閑,再加上覺得好像大家都可以實(shí)現(xiàn),也沒有什么太難的地方,也就沒有想著寫出來分享一下。
最近看見有人實(shí)現(xiàn)了一個(gè)類似的庫,而且還在各種地方發(fā)表,首先很佩服他的分享精神,也希望大家多向這樣的同學(xué)學(xué)習(xí),但是呢,看了他的源碼和說明,他的實(shí)現(xiàn)方式,感覺還是有優(yōu)化的地方,而且還有些許問題,因此和這次為DataBinding正名一樣,激起了我的保護(hù)欲,為了保護(hù)技術(shù),保護(hù)大家優(yōu)雅的使用姿勢,決定花花時(shí)間整理一下,教教大家如何優(yōu)雅的使用LiveData實(shí)現(xiàn)一套EventBus。
如果有下一篇,它將是《如何優(yōu)雅的使用LiveData實(shí)現(xiàn)一套EventBus》
~敬請(qǐng)期待~
----------------------------------------------------------- by Cody.yi
謝謝閱讀
寫得越多發(fā)現(xiàn)自己不知道的越多,如有錯(cuò)誤缺漏之處歡迎指正!
下一篇以及完成,歡迎閱讀
http://www.itdecent.cn/p/79d909b6f8bd
