一、什么是DataBinding
知道DataBinding的應該也會知道MVVM設計模式昌粤,該模式實現(xiàn)了View與Model的雙向綁定從而實現(xiàn)了View和Model的同步更新熔萧。MVVM是一種架構思想而DataBinding就是實現(xiàn)這一思想的工具磷箕。
二尝江、DataBinding的使用
我們要對DataBinding進行原理分析前吠昭,首先要會使用DataBinding傲隶。
在build.gradel中配置DataBinding
android {
...
dataBinding{
enabled true
}
}
對View的布局文件進行配置饺律,使用layout作為跟布局標簽。使用data標簽進行DataBinding的綁定跺株「幢簦控件中可以使用@{}進行綁定脖卖,@{}為單向綁定@={}為雙向綁定
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!--DataBinding的配置文件-->
<data>
<!--name屬性相當于聲明了一個全局屬性、type指定name對應的具體的數(shù)據(jù)類或是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>
聲明一個數(shù)據(jù)類巧颈,使用ObservableField聲明屬性并通過范型指定數(shù)據(jù)類型畦木。
public class UserInfo {
public ObservableField<String> userName = new ObservableField<>();
public ObservableField<String> passWord = new ObservableField<>();
}
在Activity中進行綁定
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
}
}
以上就是一個通過DataBinding實現(xiàn)雙向綁定的例子。
三砸泛、Data Binding的原理分析
我們通過上面的例子對DataBinding進行原理分析十籍。首先我們要知道DataBinding使用了apt技術,我們build項目時DataBinding會生成多個文件唇礁,我們可以在build文件中查看
DataBinding還將原有的activity_main.xml文件進行了拆分勾栗,分別是activity_mian.xml和activity_main-layout.xml。
通過上面的代碼我們發(fā)現(xiàn)DataBinding將原有的layout和data標簽去除了盏筐。并為根布局聲明了一個layout/文件名_0的tag围俘,為其他使用到@{}或@={}的控件按順序添加了一個binding_X的tag。
該配置文件中詳細的記述了<Variables declared="true" type="com.scjd.framemodel_databinding.UserInfo" name="userInfo"> 我們聲明的全局變量琢融,變量指向的數(shù)據(jù)類型的絕對路徑界牡。<Target tag="binding_1" view="EditText">tag對應的View類型。<Expression text="userInfo.userName" attribute="android:text">控件綁定具體屬性和Model中的具體屬性漾抬。<TwoWay>true</TwoWay>是否是雙向的宿亡。
接下來我們通過Activity中的 var binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)進行入手
方法中通過activity的setContentView加載布局,并通過window找到id為content的ViewGroup奋蔚,它是一個FrameLayout用于加載我們添加的布局文件她混。接下來就是bindToAddedViews方法。
parent中的子View就是我們布局文件中的根布局LinearLayout泊碑,所以走的是if中的代碼
bind方法又調用了DataBinderMapperImpl中的getDataBinder方法士嚎。
通過一系列的條件判斷之后返回了一個ActivityMainBindingImpl對象八千,接下來我們看它的構造方法。
上面的代碼看著非常的多,但是它就是將布局中的含有databinding賦值的tag控件一一存入bindings的Object的數(shù)組中并返回惧眠。
該方法中將獲取的View數(shù)組賦值給成員變量,接下來看invalidateAll()方法猖败。
上面代碼調用過來就是為了執(zhí)行mRebindRunnable没隘。在看該Runnable中的executePendingBindings()方法
上面也是對一些狀態(tài)進行了判斷添加一下回調,主要的還是executeBindings()方法窘奏。
看了上面的方法是不是有一種終于熬到頭的感覺了呢嘹锁,當((dirtyFlags & 0xeL) != 0)或((dirtyFlags & 0xdL) != 0)成立時就會把Model中的數(shù)據(jù)set到相應的View中,這個就是單向的M->V着裹。((dirtyFlags & 0x8L) != 0)成立時就是V->M它為雙向綁定的控件添加了一個內容變化的監(jiān)聽mboundView1androidTextAttrChanged
當控件中的內容發(fā)生變化時领猾,就會更新到Model上。
activity中為userInfo賦的值就是上面的mUserInfo。
通過上面的代碼我們對DataBinding的綁定過程又了一定的了解摔竿,但是還有兩個問題我們沒有解決面粮,那就是View和Model的變化有時在哪里監(jiān)聽的呢。
還記得上面的mRebindRunnable嗎继低?通過對它的查找我們在ViewDataBinding的靜態(tài)代碼塊中發(fā)現(xiàn)了端倪熬苍。
看到上面的代碼是不是一下就明白了V的變化監(jiān)聽了呢。
DataBinding通過布局中的tag將控件查找出來袁翁,然后根據(jù)生成的配置文件將V與M進行對應的同步操作柴底,設置一個全局的布局變化監(jiān)聽來實時更新,M通過他的set方法進行同步梦裂。
該文檔是自己的學習記錄如有錯誤歡迎指出似枕。