参考博文:
https://www.jianshu.com/p/076c0ea32701

https://www.jianshu.com/p/63b514a9d8ea

https://blog.csdn.net/qq_17338093/article/details/53185950

https://www.jianshu.com/p/ab9f1f937e5c

DataBindingUtil.setContentView开启源码分析之旅

核心类

DataBindingUtil

DataBindingUtil.setContentView
->
sMapper.getDataBinder

sMapper指向的是AP技术自动生成的Java类-DataBinderMapperImpl

AP生成的类

DataBinderMapperImpl (androidx.databinding目录下)

位置:androidx.databinding.DataBinderMapperImpl

package androidx.databinding;

public class DataBinderMapperImpl extends MergedDataBinderMapper {
  DataBinderMapperImpl() {
    addMapper(new com.lib.lyskinsupport.DataBinderMapperImpl());
  }
}

可以看到androidx.databinding下的DataBinderMapperImpl在自动生成的时候,会在构造方法里添加应用包名下的DataBinderMapperImpl类。

DataBinderMapperImpl (应用包名目录下)

位置:com.lib.lyskinsupport.DataBinderMapperImpl

那么,有两个问题:

第一:view.getTag是什么鬼?

第二:View对应的DataBinding类是怎么自动生成的?

自动生成xml

在编译过程中,databinding会把xml拆分为两部分,数据部分和布局部分。
- 布局部分
databinding会在build/intermediates/incremental/mergeDebugResources/stripped.dir/layout目录下自动生成传统的xml文件,和布局文件同名。如果是普通布局,则会生成和普通布局源文件一模一样的文件;如果是<layout></layout>作为根结点的databinding类布局,布局中使用了databinding的View,会自动生成tag属性,其中根结点的tag命名为layout/布局xml文件名_0,其它的view的tag自上而下命名为binding_1、binding_2...等等。
形如:

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" android:tag="layout/keyboard_layout_0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

        <TextView
            android:id="@+id/name"
            .....
            android:tag="binding_1"  />

        <ImageView
            .......
            android:tag="binding_2" />

        <TextView
            .......
            android:tag="binding_3" />

        <TextView
            .......
            android:tag="binding_4"           
            ....../>

        <TextView
            ........
            android:tag="binding_5"             
            ......./>

        <TextView
            .........
            android:tag="binding_6"  />

    </RelativeLayout>
  • 数据部分
    build\intermediates\data_binding_layout_info_type_merge\debug\out目录下会生成数据部分的xml文件,布局源文件名-layout命名。
    形如:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout directory="layout" filePath="app\src\main\res\layout\activity_db.xml"
    isBindingData="true" isMerge="false" layout="activity_db"
    modulePackage="com.lib.lyskinsupport" rootNodeType="android.widget.LinearLayout">
    <Variables name="model" declared="true" type="com.lib.lyskinsupport.viewmodel.DbViewModel">
        <location endLine="11" endOffset="64" startLine="9" startOffset="8" />
    </Variables>
    <Imports name="SkinR" type="com.lylib.skin.main.resource.SkinCompatResources">
        <location endLine="7" endOffset="69" startLine="5" startOffset="8" />
    </Imports>
    <Targets>
        <Target tag="layout/activity_db_0" view="LinearLayout">
            <Expressions>
                <Expression attribute="android:background" text="model.rootBackground">
                    <Location endLine="20" endOffset="51" startLine="20" startOffset="8" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="20" endOffset="49" startLine="20" startOffset="30" />
                </Expression>
            </Expressions>
            <location endLine="82" endOffset="18" startLine="14" startOffset="4" />
        </Target>
        <Target tag="binding_1" view="LinearLayout">
            <Expressions>
                <Expression attribute="android:background" text="model.rootBackground">
                    <Location endLine="30" endOffset="55" startLine="30" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="30" endOffset="53" startLine="30" startOffset="34" />
                </Expression>
            </Expressions>
            <location endLine="81" endOffset="22" startLine="24" startOffset="8" />
        </Target>
        <Target tag="binding_2" view="TextView">
            <Expressions>
                <Expression attribute="android:background"
                    text="1 > 0 ?@color/main_txt_bg:@color/main_txt_bg">
                    <Location endLine="72" endOffset="83" startLine="72" startOffset="16" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="72" endOffset="81" startLine="72" startOffset="38" />
                </Expression>
                <Expression attribute="android:textColor"
                    text="1 > 0 ? @color/main_bg : @color/main_txt">
                    <Location endLine="74" endOffset="78" startLine="74" startOffset="16" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="74" endOffset="76" startLine="74" startOffset="37" />
                </Expression>
            </Expressions>
            <location endLine="75" endOffset="41" startLine="69" startOffset="12" />
        </Target>
        <Target id="@+id/tv_cur_skin_info" view="TextView">
            <Expressions />
            <location endLine="37" endOffset="54" startLine="34" startOffset="12" />
        </Target>
    </Targets>
</Layout>
这两个xml文件,databinding相关的编译器是如何自动生成的呢?

这个涉及到databinding编译原理,比较复杂,可以参照:http://xinyiworld.top/wordpress/?p=5130

自动生成Binding相关的Java类

一个databinding布局xml文件,会生成一系列的binding类。假如这个布局文件为activity_db.xml

ActivityDbBinding

生成ViewModel的get方法及抽象的set方法

ActivityDbBindingImpl

->executeBindings:进行数据与View的绑定
父类ViewDataBinding有3个方法获取资源getColorFromResource、getColorStateListFromResource、getDrawableFromResource

  • 对于textColor属性
    调用ViewDataBinding的getColorFromResource方法将colorRes转化成colorInt,然后setTextColor(@ColorInt int color)设置给View。
  • 对于background属性
    1)如果设置的是colorRes,会通过ViewDataBinding的getColorFromResource将colorRes转化成colorInt,然后通过androidx.databinding.adapters.Converters.convertColorToDrawable将colorInt转化成drawable,最后通过androidx.databinding.adapters.ViewBindingAdapter.setBackground将drawable设置给View。
    2)如果设置的是colorInt,会通过androidx.databinding.adapters.Converters.convertColorToDrawable将colorInt转化成drawable,最后通过androidx.databinding.adapters.ViewBindingAdapter.setBackground将drawable设置给View。
    3)如果设置的是drawable,会直接通过androidx.databinding.adapters.ViewBindingAdapter.setBackground将drawable设置给View。

0 条评论

发表回复

您的电子邮箱地址不会被公开。