当前位置: 首页 > article >正文

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的工程,这里多了几个目录:

image.gif
不难猜出,这是DataBinding特有的目录风格。我们看到最后一个文件夹,展开会发现:

image.gif
这里的activity_main-layout.xml像极了我们activity所使用布局。点开会发现里面充满了各种标签。(如果一开始里面代码只有一行,则可以使用快捷键 Windows : ctrl+Alt + L调整代码格式)

image.gif

先列出原布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:textColor="@color/purple_200"
            android:text="@{dataInfoBean.dataInfo}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="50dp"/>

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入数据"
            android:text="@={dataInfoBean.dataInfo}"
            app:layout_constraintTop_toBottomOf="@+id/tv_data"
            android:textSize="25sp"
            android:layout_marginTop="30dp"
            android:paddingLeft="20dp"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

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

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

在intermediates/incremental目录下,相应的有效文件夹为mergeDebugResources\stripped.dir\layout 下,对应的文件名即为布局文件名:
image.gif
点开后你会发现,相较于原始的activity_main.xml布局文件,< layout>和< data>标签都消失了:

image.png
且内部控件都多了一个属性,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布局的初始化操作:

image.png
点进去查看其源码:

image.gif

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

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

image.gif
可看到最终都是调用的bind():

image.gif
这其中有个变量,sMapper。我们看到声明地方:

image.gif
可以看到此变量是由一个生成类new出来,且此类并不是原先就存在,只有在编译过程结束后才生成出来的文件:

image.gif
而在此类中最重要的就是getDataBinder(),在此方法中,可以看到拿标签流程:

image.png
通过判断是activity_main.xml的id来返回一个new ActivityMainBindingImpl(component, view);对象。我们点进去观察此对象源码:

源码图片1.png

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

源码图片2.png
源码图片3.png
此方法后续逻辑基本上都是如此,在这方法体内将所有view存进一个数组,然后在ActivityMainBindingImpl中通过bindings[1]去获取view实例:
源码图片4.png
然后通过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在内存和整体性能上的区别)


http://www.kler.cn/news/235003.html

相关文章:

  • python coding with ChatGPT 打卡第20天| 二叉搜索树:搜索、验证、最小绝对差、众数
  • GPT-4模型的创造力
  • 蓝桥杯备赛Day9——链表进阶
  • Ps:直接从图层生成文件(图像资源)
  • 《CSS 简易速速上手小册》第10章:未来的 CSS(2024 最新版)
  • 【MySQL】-21 MySQL综合-8(MySQL默认值+MySQL非空约束+MySQL查看表中的约束)
  • Ainx-V0.2-简单的连接封装与业务绑定
  • Could not connect to Redis at 127.0.0.1:6379:由于目标计算机积极拒绝,无法连接...问题解决方法之一
  • leaflet 显示自己geoserver发布的中国地图
  • WordPress修改所有用户名并发送邮件通知的插件Easy Username Updater
  • vue双向绑定的原理
  • CTF-PWN-沙箱逃脱-【侧信道爆破】(2021-蓝帽杯初赛-slient)
  • 【开源】基于JAVA+Vue+SpringBoot的实验室耗材管理系统
  • ERROR: Could not build wheels for roslz4
  • PMP-情景模拟学习法-识别时间点
  • 2.11作业
  • 图灵日记--MapSet字符串常量池反射枚举Lambda表达式泛型
  • Pandas数据预处理之数据标准化-提升机器学习模型性能的关键步骤【第64篇—python:数据预处理】
  • 深入探索Flex布局:从基础到实战,附带抖音解决方案案例分析
  • C++提高编程(黑马笔记)
  • Jedis
  • HarmonyOS 横屏调试与真机横屏运行
  • Spring Boot生成二维码的两种实现方式
  • 使用 Windows 11/10 上的最佳 PDF 转 Word 转换器释放 PDF 的潜力
  • 没更新的日子也在努力呀,布局2024!
  • sql常用函数积累(非窗口函数)
  • 从MySQL到TiDB:兼容性全解析
  • Linux(Ubuntu) 环境搭建:MySQL
  • Python中使用opencv-python进行人脸检测
  • Conda历史版本下载地址和python对应关系