type
status
date
slug
summary
tags
category
icon
password
前言基本使用在 Activity 中使用视图绑定在 Fragment 中使用视图绑定几种封装方式不使用反射使用反射ViewBindingPropertyDelegate 框架基类中使用直接在 Activity、Fragment 里面使用ViewBindingPropertyDelegate 原理简析问题内存泄露代码混淆参考文档
前言
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
- CreateMethod.INFLATE
例如下面这种使用方式,viewBinding() 默认通过反射 ActivityMainBinding.java 的
bind
方法绑定到 View,怎么获取这个 View 呢?Activity 中获取 setContentView() 所对应的这个 View 如下
Fragment 中绑定的 View 是直接 Fragment::getView() 获取。
这种方式跟上面 使用反射 小节一样。
问题
内存泄露
Fragment 中常见的一种内存泄露,例如下面这个例子,回退栈持有 Fragment 的引用,Fragment 生命周期
onDestoryView()
调用后,view 已经被移除,而且对应的 binding 对象还被 Fragment 持有引用,因此造成内存泄露。引用链条为 BackStack→Fragment→binding
示例
Test01Fragment、Test02Fragment 是 BaseFragment 子类,这样在切换后,Test01Fragment 的 binding 成员便引发了内存泄露
解决
在
onDestoryView()
时将 _binding = null
变量置空代码混淆
ViewBinding 基于 .xml 生成的视图绑定类如下
当开启代码混淆后,其中的
bind
、inflate
等方法因为混淆改变了方法名,使用反射的方式便有找不到对应方法的异常。解决
在混淆
proguard-rules.pro
配置文件里面,keep 对应的类更细粒度的配置,keep 对应的方法