Android中的DataBinding的原理淺析

一、什么是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文件中查看

圖片.png
圖片.png

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

activity_main.xml

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

activity_main-layout.xml

該配置文件中詳細(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ò)誤歡迎指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容