Android

Android中的DataBinding的原理浅析

2019-07-17  本文已影响0人  TianFB

一、什么是DataBinding

知道DataBinding的应该也会知道MVVM设计模式,该模式实现了View与Model的双向绑定从而实现了View和Model的同步更新。MVVM是一种架构思想而DataBinding就是实现这一思想的工具。

二、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对应的具体的数据类或是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>

声明一个数据类,使用PbservableField声明属性并通过范型指定数据类型。

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实现双向绑定的例子。

三、Data Binding的原理分析

我们通过上面的例子对DataBinding进行原理分析。首先我们要知道DataBinding使用了apt技术,我们build项目时DataBinding会生成多个文件,我们可以在build文件中查看

图片.png 图片.png

DataBinding还将原有的activity_main.xml文件进行了拆分,分别是activity_mian.xml和activity_main-layout.xml。

activity_main.xml

通过上面的代码我们发现DataBinding将原有的layout和data标签去除了。并为根布局声明了一个layout/文件名_0的tag,为其他使用到@{}或@={}的控件按顺序添加了一个binding_X的tag。

activity_main-layout.xml

该配置文件中详细的记述了<Variables declared="true" type="com.scjd.framemodel_databinding.UserInfo" name="userInfo"> 我们声明的全局变量,变量指向的数据类型的绝对路径。<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的数组中并返回。

该方法中将获取的View数组赋值给成员变量,接下来看invalidateAll()方法。

上面代码调用过来就是为了执行mRebindRunnable。在看该Runnable中的executePendingBindings()方法

上面也是对一些状态进行了判断添加一下回调,主要的还是executeBindings()方法。

看了上面的方法是不是有一种终于熬到头的感觉了呢,当((dirtyFlags & 0xeL) != 0)或((dirtyFlags & 0xdL) != 0)成立时就会把Model中的数据set到相应的View中,这个就是单向的M->V。((dirtyFlags & 0x8L) != 0)成立时就是V->M它为双向绑定的控件添加了一个内容变化的监听mboundView1androidTextAttrChanged

当控件中的内容发生变化时,就会更新到Model上。

activity中为userInfo赋的值就是上面的mUserInfo。
通过上面的代码我们对DataBinding的绑定过程又了一定的了解,但是还有两个问题我们没有解决,那就是View和Model的变化有时在哪里监听的呢。

还记得上面的mRebindRunnable吗?通过对它的查找我们在ViewDataBinding的静态代码块中发现了端倪。

看到上面的代码是不是一下就明白了V的变化监听了呢。

DataBinding通过布局中的tag将控件查找出来,然后根据生成的配置文件将V与M进行对应的同步操作,设置一个全局的布局变化监听来实时更新,M通过他的set方法进行同步。

该文档是自己的学习记录如有错误欢迎指出。

上一篇下一篇

猜你喜欢

热点阅读