Nitro's

Oct 25, 2016 - Comments - tech dev

Android Data Binding代码分析

Android团队推出Data Binding支持已经一年有余,但碍于项目已经在使用原始setXXX的方式,想要完全替换需要一定时间,一直没有进入todo list。最近在一个小demo中试验了一下。详细的开发示例不再赘述,可以参考Android Dev官网的代码示例,中文版可以参考简书的一篇比较新鲜的译文

这里主要分析一下Data Binding的生成代码和binding过程分析,请确保Support Repository(39)、Support Library(23.2.1)、Gradle plugin(2.2.2)、Gradle(2.14.1)、Android Studio(2.2.2)更新到最新版本。

Data Binding的代码生成由Android Gradle插件根据Layout XML来生成。

示例XML activity_bind.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>

对应生成代码结构

package:android.databinding

DataBinderMapper.java     //实现Layout的映射

InnerBrLookup—存储BR文件中成员变量名与索引的对应关系

convertBrIdToString()—根据BR文件成员变量索引转换出model成员变量名

getLayoutId()—根据Data binding的Layout tag转换Layout Resource ID

getDataBinder()—执行bind并返回对应的binding对象

DataBindingComponent.java

DynamicUtil.java                 //数值转换、版本相关特殊处理工具类

package:com.android.databinding.library.baseAdapters

BR.java                             //类似于R文件,data层model类的int映射

package:apkPackageName.binding

_ActivityBind_Binding.java        //Data Bind的关键的关键,继承自ViewDataBinding,与XML文件名保持一致

bind()—activity对View的写入和获取,在验证XML后,最终通过_ActivityBind_Binding的构造方法获取到对应的绑定View。

inflate()—与bind()类似,通过LayoutInflater获取到View进行bind()

executeBindings()—执行model层的数据写入,写入是通过一系列adpter根据android:xxx标签的实现方法一一对应写入,具体的adapter参见后续。

BR.java                            //类似于R文件,data层model类的int映射

对应打包文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        android:layout_height="fill_parent" 
        android:layout_width="fill_parent"
        android:orientation="vertical"
        android:tag="layout/activity_bind_0" 
        xmlns:android="http://schemas.android.com/apk/res/android">
        <TextView 
            android:layout_height="wrap_content"
            android:layout_width="wrap_content" 
            android:tag="binding_1" />
        <TextView
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:tag="binding_2" />
    </LinearLayout>

通过打包后的文件查看,我们可以发现和没有使用data binding的XML基本没有区别,只有两点不太一样:

1、每个需要binding的View上多了一个tag标签;

其实在data binding的过程中android:tag标签发挥了重大作用,所有的待binding View都是通过tag来交互的,而且tag的名字有固定格式:root View的tag是”layout/_layoutxmlname__0”,其他View的tag是binding_1,2,3…..,格式可以参考android.databinding.ViewDataBinding.mapBindings()方法,这里有详细的解析过程。

可能我们还会有另外一个疑问,如果本身View需要设置tag,那岂不是会被覆盖,Android团队考虑到这一点,在生成binding的代码中有对XML中手动设置tag的处理操作:binding的XML处理规则不变,binding后通过硬编码的方式调用View的setTag()再写入一次,这样就保证了binding规则不变,tag同样能够生效。

2、设置的setText属性不见了踪影。

setText虽然在XML中消失了,但它的设置被转移到了Binding的过程中,就是上面提到的executeBindings()中。当前Android官方给出的data binding库中支持37个组件,基本覆盖了常用的组件库,对这些组件的属性绑定支持是通过一系列的adapter来实现的,比如TextView对应的adapter是android.databinding.adapters.TextViewBindingAdapter。在每一个adapter中通过注解实现了各自组件的很多属性,这样通过XML解析到需要binding的属性,直接生成相应的方法调用,比如android:text<==>textView.setText()。其他组件的adapter实现参见源代码

事件绑定、表达式,还没有具体深入使用后续继续跟进。

android-data-binding

Tags: android

山后-零零 Android TextInputLayout升级后的坑

comments powered by Disqus