② Kotlin委托 + lifecycle组件
有些朋友可能觉得写在父类中侵入性太强,接着试下用其他方式进行封装,先看原始Activity:
要把圈住的代码干掉,先是 泛型传递问题,泛型在进JVM前会被擦除,可在运行时通过反射获得,还可以通过实例化类类型代替类引用,如:
fun <T: Activity> FragmentActivity.startActivity(context: Context, clazz: Class<T>) { startActivity(Intent(context, clazz)) } // 调用处 startActivity(context, MainActivity::class.java)
而在Kotlin中还可以用 inline 定义一个 内联函数 (编译时自动替换到调用位置),配合 reified 具体化(类型不擦除),得到泛型类型的Class,如:
inline fun <reified T : Activity> Activity.startActivity(context: Context) { startActivity(Intent(context, T::class.java)) } // 调用 startActivity<MainActivity>(context)
可以,配合反射invoke()调用,随手写上一个扩展方法:
调用下:
看似十拿九稳,结果一跑就崩:
不过也在意料之内,Activity还没onCreate()就初始化了,不空才怪,可以利用 标准委
托-lazy 延迟初始化,修改后的代码:
调用下:
运行通过,你还可以把还可以把setContentView()也塞到扩展中:
配合lifecycle组件,顺手把Fragment的也写出来:
调用下:
对了,如果还不想使用反射,可以利用Kotlin高阶函数,示例如下:
调用下:
啧啧啧,你还可以不用lazy,自己重写ReadOnlyProperty,这里只是试试水封装,并没用到生产上,更完善的封装方案可自行参考下述开源库:
0x5、原理
AGP会为模块中每个XML生成一个绑定类,该类的实例会直接引用布局中声明了资源id的View
① 自动生成的绑定类
打开:module模块名/build/generated/intermediates/javac/渠道/包名/databinding
可以看到 (基于AGP 7.1.1,不同AGP版本可能不一样):
自动生成的class文件,随手打开一个:
所以本质上还是findViewById,只是自动生成了控件实例,并一一对应,接着简单了解下大概的生成流程。
② 生成Java类
执行gradlew assembleDebug,在Task构建列表没找到ViewBinding,却找到了DataBinding:
打开AGP源码,全局搜 dataBindingMergeGenClasses → DataBindingMergeBaseClassLogTask.kt
跟到:TaskManager.kt → createDataBindingTasksIfNecessary
2333,跟DataBinding混一起了,所以 ViewBinding其实只是DataBinding功能的一小部分~
看回:DataBindingMergeBaseClassLogTask,增量和全量执行动作:
跟下:DataBindingMergeBaseClassLogDelegate
跟下:DataBindingMergeBaseClassLogRunnable
判断文件是否新建、修改、或移除,跟下是哪个文件:
全局搜下这个结尾的文件,在下述目录找到了它:
不难看出是:XML名称和ViewBinding类的映射,往下看 DataBindingMergeDependencyArtifactsTask,BR相关的,目前不知道是干嘛的。
再往下走:DataBindingGenBaseClassesTask → CreationAction:
跟下:DataBindingGenBaseClassesTask → @TaskAction
先看 buildInputArgs(),构建输入参数,同样对增量和全量编译进行了不同的处理,然后返回配置实例
接着看 CodeGenerator 类,见名知意,代码生成器:
这里直接索引不到 BaseDataBinder
,需要另外依赖:databinding-compiler-common
implementation 'androidx.databinding:databinding-compiler-common:7.1.0'
async后就可以了,打开 MVNResponsitory - Gradle » 7.1.0 可以看到它依赖了47个运行时库~
跟下:BaseDataBinder → generateAll()
跟下:ViewBinderGenerateJava.kt → toJavaFile() → JavaFileGenerator
Java文件就是从这里构造出来的,具体构造过程,感兴趣的可以自己翻阅下此文件。
另外,如果你想了解布局采集和写Layout部分的逻辑,可以参考 《ViewBinding 的本质》,笔者卷不动了...
0x6、一些补充
① 与DataBinding的区别
可以把ViewBinding看做DataBinding功能的子集,它有的功能DataBinding都有,不需要数据绑定,单纯想替代findViewById 可以用ViewBinding。
② 不用build就能自动生成Java类
笔者猜测:AS起了一个进程 Filesystem events processor 用于监听文件变化,有文件变动时回调执行ViewBinding相关的Task。
③ KAE库过时,迁移Parcelable
Module 层次的 build.gradle 添加 kotlin-parcelize 插件。
以上就是本节的全部内容,有疑问或补充欢迎评论区指出,谢谢~
参考文献:
- 是时候更新手里的武器了—Jetpack最全简析
- Android Jetpack Architecture Components
- 是时候拥抱ViewBinding了!!
- Android | ViewBinding 与 Kotlin 委托双剑合璧
- ViewBinding 巧妙的封装思路,还能这样适配 BRVAH
- Android View Binding使用详解
- Kotlin 插件的落幕,ViewBinding 的崛起
- ViewBinding 基类编写
- 译:深入研究ViewBinding 在 include, merge, adapter, fragment, activity 中使用
- ViewBinding 的本质