目录

View Binding 大致原理简易分析

View Binding 大致原理简易分析

1. 简易介绍

ViewBinding 是 Android 中的一种视图绑定的工具,可以给 layout xml 动态创建属于它的 Layout Binding Class,不过我们应该关注一下这个东西是怎么实现的,我们要分为编译前和编译后:

  • 编译前:
    1. KAE: 分析 XML 文件,通过 IDE 插件(Kotlin) SyntheticResolveExtension 创建 Synthetic 语句(替换为 findViewById)
    2. ViewBinding: 分析 XML 文件,通过 IDE 插件(Android) shortNamesCache,customUsageSearcher,resolveScopeEnlarger 等来实现实时创建 Layout Binding Class
  • 编译后:
    1. KAE: 通过 kotlin compiler plugin,修改 JVM ByteCode/IR,编织入类似 findViewById 这种代码,本质上和 kotlin data class 的 copy 方法的实现原理是类似的
    2. ViewBinding: 生成 Binding 类,并于项目中其他代码一同参与编译

所以其实 ViewBinding 是要比 KAE 更加低效的,当然肯定都不如直接写 findViewById 效率高(

简易分析

通过 ViewBinding(以下简称 VB) 的创建方式涉及到的类我们大致可以猜测这东西是位于 DataBinding repo 的,VB 只是用到了其中一部分功能,因此我们需要找到 DataBinding(以下简称 DB) 的源码,由于 DB/VB 在引入时需要我们在 build.gradle 中进行配置:

1
2
3
4
5
android {
    viewBinding {
        enabled = true
    }
}

因此我们就可以去看看 AGP 的 repo:

首先我们可以去 Maven Repository: Search/Browse/Explore (mvnrepository.com),找到 AGP,我们也知道 VB 是在 AGP 3.6 之后的版本引入的,于是可以在其依赖类里面发现:https://cdn.jsdelivr.net/gh/zsqw123/cdn@master/picCDN/screenshot-20220320-140136.png

第一个就是 DB,同时查看这个东西的反向依赖也能发现其 compiler, 我们发现这是个注解处理器,会在编译时动态生成 classhttps://cdn.jsdelivr.net/gh/zsqw123/cdn@master/picCDN/screenshot-20220320-140934.png

这些都是给编译器用的,如果要做到实时提示的话,要依赖 IDE 的支持,我们也可以找到与 AGP 搭配食用的 IDEA Android Plugin: JetBrains/android: Android Plugin for IntelliJ IDEA (github.com),不过项目是使用 Google 内部比较常用的 bazel 进行构建的,而不是 Gradle,这里我们可以对项目进行一些改造方便我们在 IDEA 中查看源码以及引用跳转,我这里有一份自己的改造:zsqw123/DataBinding-IDEA-Plugin,可以直接在 IDEA 中打开和智能提示

2. IDE Plugin 分析

对于任何一个 IDEA Plugin,我们都可以在 META-INF 中找到插件配置 .xml 文件,在 DB 的 .xml 中,我筛选了几个 ViewBinding 主要用到的这些扩展,每一个扩展事实上都是定义了一个接口/抽象类,我们实现相应的扩展就是去实现指定的接口并在这里进行注册。

1
2
3
4
5
6
7
<java.shortNamesCache implementation="..LayoutBindingShortNamesCache"/>
<resolveScopeEnlarger implementation="..BindingScopeEnlarger" />
<java.elementFinder implementation="..BindingClassFinder" />
<moduleService serviceImplementation="..LayoutBindingModuleCache" />

<customUsageSearcher implementation="..DataBindingResourceUsageSearcher"/>
<automaticRenamerFactory implementation="..DataBindingRenamerFactory"/>

这几个扩展的大致流程是:

接下来我们就来说说这几个扩展的作用:

shortNamesCache

用于 Code Completion,在输入非全类名时,提示出项目中的文件以及 Class,Method,Field 等,并进行 suggesting import

resolveScopeEnlarger

虚拟生成的 class 存在于 Light VirtualFileSystem 中,并不是项目源码所在的位置,如果我们要让 IDE 找到这些虚拟生成的 class,我们就需要通过 ResolveScopeEnlargerKotlinResolveScopeEnlarger 实现

elementFinder

这个扩展可以实现按 qualifiedName 定位类或包,在 VB 中,activity_main.xml 将会找到其生成的类 ActivityMainBinding

moduleService

针对 Module 注册的服务,在 VB 中,在 DB 中的这个 LayoutBindingModuleCache 中,通过 getLightBindingClasses 真正生成了 LightBindingClass

其他

  • customUsageSearcher 用来找到 Usage 引用,在重构时方便找到关联的引用
  • automaticRenamerFactory 用于重构,方便批量重命名引用

3. 参考