一、什么是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 图片.pngDataBinding还将原有的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方法进行同步。
该文档是自己的学习记录如有错误欢迎指出。
网友评论