一、什么是DataBinding
知道DataBinding的應(yīng)該也會(huì)知道MVVM設(shè)計(jì)模式,該模式實(shí)現(xiàn)了View與Model的雙向綁定從而實(shí)現(xiàn)了View和Model的同步更新。MVVM是一種架構(gòu)思想而DataBinding就是實(shí)現(xiàn)這一思想的工具。
二、DataBinding的使用
我們要對(duì)DataBinding進(jìn)行原理分析前,首先要會(huì)使用DataBinding。
在build.gradel中配置DataBinding
android {
...
dataBinding{
enabled true
}
}
對(duì)View的布局文件進(jìn)行配置,使用layout作為跟布局標(biāo)簽。使用data標(biāo)簽進(jìn)行DataBinding的綁定??丶锌梢允褂聾{}進(jìn)行綁定,@{}為單向綁定@={}為雙向綁定
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!--DataBinding的配置文件-->
<data>
<!--name屬性相當(dāng)于聲明了一個(gè)全局屬性、type指定name對(duì)應(yīng)的具體的數(shù)據(jù)類(lèi)或是MVVM中VM-->
<variable
name="userInfo"
type="com.scjd.framemodel_databinding.UserInfo"/>
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
android:padding="50dp"
android:orientation="vertical">
<EditText android:layout_width="match_parent" android:layout_height="wrap_content"
android:text="@={userInfo.userName}"/>
<EditText android:layout_width="match_parent" android:layout_height="wrap_content"
android:text="@{userInfo.passWord}"/>
<View android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
聲明一個(gè)數(shù)據(jù)類(lèi),使用ObservableField聲明屬性并通過(guò)范型指定數(shù)據(jù)類(lèi)型。
public class UserInfo {
public ObservableField<String> userName = new ObservableField<>();
public ObservableField<String> passWord = new ObservableField<>();
}
在Activity中進(jìn)行綁定
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
var userInfo = UserInfo()
userInfo.userName.set("xixi")
userInfo.passWord.set("123")
binding.userInfo = userInfo
}
}
以上就是一個(gè)通過(guò)DataBinding實(shí)現(xiàn)雙向綁定的例子。
三、Data Binding的原理分析
我們通過(guò)上面的例子對(duì)DataBinding進(jìn)行原理分析。首先我們要知道DataBinding使用了apt技術(shù),我們build項(xiàng)目時(shí)DataBinding會(huì)生成多個(gè)文件,我們可以在build文件中查看


DataBinding還將原有的activity_main.xml文件進(jìn)行了拆分,分別是activity_mian.xml和activity_main-layout.xml。

通過(guò)上面的代碼我們發(fā)現(xiàn)DataBinding將原有的layout和data標(biāo)簽去除了。并為根布局聲明了一個(gè)layout/文件名_0的tag,為其他使用到@{}或@={}的控件按順序添加了一個(gè)binding_X的tag。

該配置文件中詳細(xì)的記述了<Variables declared="true" type="com.scjd.framemodel_databinding.UserInfo" name="userInfo"> 我們聲明的全局變量,變量指向的數(shù)據(jù)類(lèi)型的絕對(duì)路徑。<Target tag="binding_1" view="EditText">tag對(duì)應(yīng)的View類(lèi)型。<Expression text="userInfo.userName" attribute="android:text">控件綁定具體屬性和Model中的具體屬性。<TwoWay>true</TwoWay>是否是雙向的。
接下來(lái)我們通過(guò)Activity中的 var binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)進(jìn)行入手

方法中通過(guò)activity的setContentView加載布局,并通過(guò)window找到id為content的ViewGroup,它是一個(gè)FrameLayout用于加載我們添加的布局文件。接下來(lái)就是bindToAddedViews方法。

parent中的子View就是我們布局文件中的根布局LinearLayout,所以走的是if中的代碼


bind方法又調(diào)用了DataBinderMapperImpl中的getDataBinder方法。

通過(guò)一系列的條件判斷之后返回了一個(gè)ActivityMainBindingImpl對(duì)象,接下來(lái)我們看它的構(gòu)造方法。





上面的代碼看著非常的多,但是它就是將布局中的含有databinding賦值的tag控件一一存入bindings的Object的數(shù)組中并返回。

該方法中將獲取的View數(shù)組賦值給成員變量,接下來(lái)看invalidateAll()方法。



上面代碼調(diào)用過(guò)來(lái)就是為了執(zhí)行mRebindRunnable。在看該Runnable中的executePendingBindings()方法


上面也是對(duì)一些狀態(tài)進(jìn)行了判斷添加一下回調(diào),主要的還是executeBindings()方法。


看了上面的方法是不是有一種終于熬到頭的感覺(jué)了呢,當(dāng)((dirtyFlags & 0xeL) != 0)或((dirtyFlags & 0xdL) != 0)成立時(shí)就會(huì)把Model中的數(shù)據(jù)set到相應(yīng)的View中,這個(gè)就是單向的M->V。((dirtyFlags & 0x8L) != 0)成立時(shí)就是V->M它為雙向綁定的控件添加了一個(gè)內(nèi)容變化的監(jiān)聽(tīng)mboundView1androidTextAttrChanged

當(dāng)控件中的內(nèi)容發(fā)生變化時(shí),就會(huì)更新到Model上。

activity中為userInfo賦的值就是上面的mUserInfo。
通過(guò)上面的代碼我們對(duì)DataBinding的綁定過(guò)程又了一定的了解,但是還有兩個(gè)問(wèn)題我們沒(méi)有解決,那就是View和Model的變化有時(shí)在哪里監(jiān)聽(tīng)的呢。
還記得上面的mRebindRunnable嗎?通過(guò)對(duì)它的查找我們?cè)赩iewDataBinding的靜態(tài)代碼塊中發(fā)現(xiàn)了端倪。

看到上面的代碼是不是一下就明白了V的變化監(jiān)聽(tīng)了呢。
DataBinding通過(guò)布局中的tag將控件查找出來(lái),然后根據(jù)生成的配置文件將V與M進(jìn)行對(duì)應(yīng)的同步操作,設(shè)置一個(gè)全局的布局變化監(jiān)聽(tīng)來(lái)實(shí)時(shí)更新,M通過(guò)他的set方法進(jìn)行同步。
該文檔是自己的學(xué)習(xí)記錄如有錯(cuò)誤歡迎指出。