ViewBinding 封装
2024-6-16
| 2024-6-21
0  |  Read Time 0 min
type
status
date
slug
summary
tags
category
icon
password

前言

ViewBinding 视图绑定功能可让您更轻松地编写与视图交互的代码。在模块中启用视图绑定后,它会为该模块中显示的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。ViewBinding 优点和配置方式见于 视图绑定

基本使用

在 Activity 中使用视图绑定

在 Fragment 中使用视图绑定

如上代码所示,如果有很多 Fragment,每一个都要拷贝一份相同的代码,不符合 Don't repeat yourself 的原则,所以尝试对其进行封装。

几种封装方式

不使用反射

BaseActivity,使用泛型 <VB : ViewBinding>ActivityMainBinding::inflate 函数作为参数传递给 BaseActivity。
BaseFragment,onDestroyView()_binding = null 以避免内存泄露。
Activity 中使用示例
Fragment 中使用示例

使用反射

在基类中通过反射调用 ActivityMainBinding.java (ViewBinding 编译后生成的类)中的 inflate 方法获取视图 View。
BaseActivity 定义
BaseFragment 定义

ViewBindingPropertyDelegate 框架

使用 ViewBindingPropertyDelegate 开源框架,在 module 下的 build.gradle 文件里引入

基类中使用

BaseActivity 定义
BaseFragment 定义
Activity 中使用示例
Fragment 中使用示例

直接在 Activity、Fragment 里面使用

ViewBindingPropertyDelegate 原理简析

  • kotlin 的委托
本质上使用了 kotlin 的委托,关于 kotlin 委托,这篇 一文彻底搞懂Kotlin中的委托 博客写的很好。拿对 Fragment 处理举例
  • 布局与 Binding 对象建立关联
    • CreateMethod.BIND
      • 例如下面这种使用方式,viewBinding() 默认通过反射 ActivityMainBinding.java 的 bind 方法绑定到 View,怎么获取这个 View 呢?
        Activity 中获取 setContentView() 所对应的这个 View 如下
        Fragment 中绑定的 View 是直接 Fragment::getView() 获取。
    • CreateMethod.INFLATE
      • 这种方式跟上面 使用反射 小节一样。

问题

内存泄露

Fragment 中常见的一种内存泄露,例如下面这个例子,回退栈持有 Fragment 的引用,Fragment 生命周期 onDestoryView() 调用后,view 已经被移除,而且对应的 binding 对象还被 Fragment 持有引用,因此造成内存泄露。引用链条为 BackStack→Fragment→binding
示例
Test01Fragment、Test02Fragment 是 BaseFragment 子类,这样在切换后,Test01Fragment 的 binding 成员便引发了内存泄露
notion image
 
 
解决
onDestoryView() 时将 _binding = null 变量置空

代码混淆

ViewBinding 基于 .xml 生成的视图绑定类如下
当开启代码混淆后,其中的 bindinflate 等方法因为混淆改变了方法名,使用反射的方式便有找不到对应方法的异常。
解决
在混淆 proguard-rules.pro 配置文件里面,keep 对应的类
更细粒度的配置,keep 对应的方法

参考文档

 
 
  • Android
  • Android AIDL 服务端客户端双向死亡监听和”连接后执行”的几种尝试ZoomImageView 实现指南(上篇)
    • Utterance
    Catalog