DataBinding源码浅析---初始化过程

作为Google官方发布的支持库,DataBinding实现了UI组件和数据源的双向绑定,同时在Jetpack组件中,也将DataBinding放在了Architecture类型之中。对于DataBinding的基础使用请先翻阅前两篇文章的详细阐述。本文所用代码也是建立在之前工程基础之上。

初始化分析

按照官方文档所说,Databinding在编译期会生成代码,利用的技术是Apt(annotation-processing-tool)。在运行完工程后,可以看到build文件夹下生成多个文件夹和文件,看到了这里,就可以明白其核心原理肯定跟注解处理器有关系,其实所有通过APT生成代码的框架(比如ButterKnife,dagger2,hit等),大多数情况下其核心逻辑的实现都在生成代码中,可以说其完全就是通过注解处理器产生的,因此需要我们重点翻阅的都是生成的代码。在我们按照规则写完布局文件后,会生成相应的.java文件,文件名为xml文件名加上Binding后缀。原工程则生成是的ActivityMainBinding.java文件,这点不难理解。

从XML开始

让我们关注build目录下的intermediates目录,你会发现,相较于其他没有使用Data Binding的工程,这里多了几个目录:

DataBinding源码浅析---初始化过程_第1张图片
不难猜出,这是DataBinding特有的目录风格。我们看到最后一个文件夹,展开会发现:

DataBinding源码浅析---初始化过程_第2张图片
这里的activity_main-layout.xml像极了我们activity所使用布局。点开会发现里面充满了各种标签。(如果一开始里面代码只有一行,则可以使用快捷键 Windows : ctrl+Alt + L调整代码格式)

DataBinding源码浅析---初始化过程_第3张图片

先列出原布局文件:




    
        
        
    

    

        

        

    

可以看出这里面总共三个控件,对应activity_main-layout.xml中有三个< target>节点。

DataBinding源码浅析---初始化过程_第4张图片
节点里view属性名称则刚好可以是我们布局中所用控件,这里就是我们在布局中声明的控件无疑。在这些< target>信息中,还可看到所赋予的tag信息(binding_1、binding_2)。而在Expression标签中,text对应属性值里有“dataInfoBean.dataInfo”这就刚好对应上数据来源。当然,仅仅靠这个文本,是不可能生成一个能绘制出来的效果。这时还要观察另外一个文件。

在intermediates/incremental目录下,相应的有效文件夹为mergeDebugResources\stripped.dir\layout 下,对应的文件名即为布局文件名:
DataBinding源码浅析---初始化过程_第5张图片
点开后你会发现,相较于原始的activity_main.xml布局文件,< layout>和< data>标签都消失了:

DataBinding源码浅析---初始化过程_第6张图片
且内部控件都多了一个属性,android:tag属性。此tag属性所赋id则跟build/intermediates/data_binding_layout_info_type_package/debug/out/activity_main-layout.xml中的标签里的tag相对应。不难猜出,其xml具体显示流程与这俩文件紧密相关。

接下来就要去看整体的流程了。

初始化流程

要分析整体流程还得从MainActivity入手,DataBindingUtil.setContentView(this, R.layout.activity_main);就是完成XML布局的初始化操作:

DataBinding源码浅析---初始化过程_第7张图片
点进去查看其源码:

DataBinding源码浅析---初始化过程_第8张图片

DataBinding源码浅析---初始化过程_第9张图片
可以发现这里通过获取Window的decorView,来把传进来的layoutId(即我们的布局)通过bindToAddedViews()绑定到屏幕视图上。这里的contentView和其id.content是工程创建时Activity就自带的默认FrameLayout,对这个不了解的要去了解下屏幕渲染机制,在这里不需要纠结。

继续观察bindToAddedViews()内部对于绑定的过程实现:

DataBinding源码浅析---初始化过程_第10张图片
可看到最终都是调用的bind():

DataBinding源码浅析---初始化过程_第11张图片
这其中有个变量,sMapper。我们看到声明地方:

DataBinding源码浅析---初始化过程_第12张图片
可以看到此变量是由一个生成类new出来,且此类并不是原先就存在,只有在编译过程结束后才生成出来的文件:

DataBinding源码浅析---初始化过程_第13张图片
而在此类中最重要的就是getDataBinder(),在此方法中,可以看到拿标签流程:

DataBinding源码浅析---初始化过程_第14张图片
通过判断是activity_main.xml的id来返回一个new ActivityMainBindingImpl(component, view);对象。我们点进去观察此对象源码:

DataBinding源码浅析---初始化过程_第15张图片

可以看出,对应取控件id等操作来源得看mapBindings内部实现:

DataBinding源码浅析---初始化过程_第16张图片
DataBinding源码浅析---初始化过程_第17张图片
此方法后续逻辑基本上都是如此,在这方法体内将所有view存进一个数组,然后在ActivityMainBindingImpl中通过bindings[1]去获取view实例:
DataBinding源码浅析---初始化过程_第18张图片
然后通过invalidateAll()更新所有UI。

以上不难看出这些流程就是XML布局的初始化所有流程。在初始化结束后,xml的控件信息就存在了DataBinding对象里,就可以通过DataBinding对象拿到具体对应控件对象实例了。

ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
viewDataBinding.tvData.setText("拿到对象实例了");

这也正是为什么DataBinding可以不用findViewById了的原因。其实不难想到,随着页面的UI复杂度的增加,dataBinding对内存的消耗也会越大,个人感觉这是DataBinding的缺点。(后面有时间,我会去对比DataBinding与常规架构所构建的APP在内存和整体性能上的区别)

你可能感兴趣的:(Android进阶,android,jetpack,android-jetpack,android,kotlin)