ViewBinding使用入门
ViewBinding
参考资料:
新技术 ViewBinding 最佳实践 & 原理击穿
更多 ViewBinding 的封装思路
1. kotlin-android-extensions(KAE) 的问题
根据Google官方的说法, KAE存在以下问题:
- 污染全局命名空间
- 不能暴露
可空性信息 - 仅支持Kotlin代码
kotlin在1.4.20中 开始废弃这个库了(https://blog.jetbrains.com/kotlin/2020/11/kotlin-1-4-20-released/#Deprecation_of_Kotlin_Android_Extensions)
ReleaseNote中的原因是 KAT所填补的空白已经被ViewBinding所代替了, 所以他们不再支持了…
2. ViewBinding的使用
1. 开启ViewBinding
在model的build.gradle 中开启
android {viewBinding {enabled = true}
}
之后每个xml布局都会生成对应ViewBinding类
如果想要忽略摸个布局文件, 可以添加tools:viewBindingIgnore="true"属性
<LinearLayout...tools:viewBindingIgnore="true" >...</LinearLayout>
2. 基本用法
生成的ViewBinding类使用以下方式的命名规则:将 XML 文件的名称转换为驼峰式大小写,并在末尾添加“Binding”一词
例如, 有如下布局 名称为result_profile.xml:
<LinearLayout ... ><TextView android:id="@+id/name" /><ImageView android:cropToPadding="true" /><Button android:id="@+id/button"android:background="@drawable/rounded_button" />
</LinearLayout>
所生成的绑定类的名称就为 ResultProfileBinding。此类具有两个字段:一个是名为 name 的 TextView,另一个是名为 button 的 Button。该布局中的 ImageView 没有 ID,因此绑定类中不存在对它的引用。
每个绑定类还包含一个 getRoot() 方法,用于为相应布局文件的根视图提供直接引用。在此示例中,ResultProfileBinding 类中的 getRoot() 方法会返回 LinearLayout 根视图。
每一个Binding类都提供了3中创建ViewBinding对象的方式, 可以根据情况选择:

位置:

ViewBinding的用法基本上都是在围绕着上面的3个方法
2.1 在Activity中只用
- 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Activity 使用。
- 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
- 将根视图传递到 setContentView(),使其成为屏幕上的活动视图。
private lateinit var binding: ResultProfileBindingoverride fun onCreate(savedInstanceState: Bundle) {super.onCreate(savedInstanceState)binding = ResultProfileBinding.inflate(layoutInflater)val view = binding.rootsetContentView(view)}
然后就可以使用对应的View了
binding.name.text = viewModel.namebinding.button.setOnClickListener { viewModel.userClicked() }
2.2 在Fragment中使用
- 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Fragment 使用。
- 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
- 从 onCreateView() 方法返回根视图,使其成为屏幕上的活动视图。
private var _binding: ResultProfileBinding? = null// This property is only valid between onCreateView and// onDestroyView.private val binding get() = _binding!!override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {_binding = ResultProfileBinding.inflate(inflater, container, false)val view = binding.rootreturn view}override fun onDestroyView() {super.onDestroyView()_binding = null}
2.3 在Adapter中使用ViewBinding
在Adapter中使用ViewBinding与之前没有什么不同
class SimpleDataAdapter : RecyclerView.Adapter<SimpleDataAdapter.ViewHolder>() {var dataList: List<Data> = emptyList()set(value) {field = valuenotifyDataSetChanged()}inner class ViewHolder(binding: ItemDataBinding) : RecyclerView.ViewHolder(binding.root) {val dataIv = binding.dataIvval dataTv = binding.dataTv}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {val binding = ItemDataBinding.inflate(LayoutInflater.from(parent.context), parent, false)return ViewHolder(binding)}override fun onBindViewHolder(holder: ViewHolder, position: Int) {dataList[position].let {holder.dataIv.setImageResource(it.img)holder.dataTv.text = it.txt}}override fun getItemCount(): Int = dataList.size
}
2.4 对引入布局使用ViewBinding
2.4.1 include
比如有如下布局: titlebar.xml 希望作为一个通用布局引入到其他布局中
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><Buttonandroid:id="@+id/back"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:text="Back" /><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="Title"android:textSize="20sp" /><Buttonandroid:id="@+id/done"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:text="Done" /></RelativeLayout>
activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><includeandroid:id="@+id/titleBar"layout="@layout/titlebar" />
</LinearLayout>
Activity中使用
class IncludeActivity : AppCompatActivity() {private lateinit var binding: ActivityIncludeBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityIncludeBinding.inflate(layoutInflater)setContentView(binding.root)binding.titleBar.title.text = "Title"binding.titleBar.back.setOnClickListener {}binding.titleBar.done.setOnClickListener {}}}
这里可以看到 binding中根据id生成了一个titleBar的对象, 查看ViewBinding生成的代码可知, 这个titleBar还是一个ViewBinding的类:

2.4.2 merge
如果被引入的布局根标签是merge, 则不能使用上述方式了, 疑问merge会将被引入的布局直接合并到对应的位置, 所以在ViewBinding中, 通过id找对应的ViewBinding的过程中会失败

相较于2.4.1的代码:
- 删除include标签上的id属性
- 在kotlin代码中, 自己赋值ViewBinding对象:
class MergeActivity : AppCompatActivity() {private lateinit var binding: ActivityMergeBindingprivate lateinit var titlebarBinding: TitlebarMergeBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMergeBinding.inflate(layoutInflater)setContentView(binding.root)titlebarBinding = TitlebarMergeBinding.bind(binding.root)titlebarBinding.title.text = "Title"titlebarBinding.back.setOnClickListener {}titlebarBinding.done.setOnClickListener {}}}
3. 封装
封装的主要思路是尽量不写,或少写一些模板代码, 主要的思路就是在创建ViewBinding对象上实现自动创建
3.1 Activity
open class BaseReflectionAty<VB : ViewBinding> : AppCompatActivity() {protected lateinit var binding: VBprivate setoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)generateViewBinding()if (this::binding.isInitialized) {setContentView(binding.root)binding.initViews()}}open fun VB.initViews() {}/*** 生成ViewBinding*/private fun generateViewBinding() {val type = this::class.java.genericSuperclass as? ParameterizedType ?: returnval vbClazz = type.actualTypeArguments.find {// 找到泛型声明为 实现了 ViewBinding接口的类型(it as Class<*>).genericInterfaces[0] == ViewBinding::class.java} as? Class<*> ?: returnval method = vbClazz.getMethod("inflate", LayoutInflater::class.java)binding = method.invoke(null, layoutInflater) as VB}
}
在onCreate时, 通过generateViewBinding方法来生成对应的ViewBinding对象,使用时:
class MainActivity : BaseReflectionAty<ActivityMainBinding>() {override fun ActivityMainBinding.initViews() {mainTextView.setOnClickListener {Toast.makeText(this@MainActivity, "lalala", Toast.LENGTH_SHORT).show()}}
}
直接在initViews中使用布局文件中东的View即可
3.2 Fragment
Fragment的思路与Activity相同
class BaseReflectionFragment<VB : ViewBinding> : Fragment() {private var _binding: VB? = nullprotected val binding: VBget() = _binding!!override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {generateViewBinding(container)if (_binding != null) {return binding.root}return super.onCreateView(inflater, container, savedInstanceState)}open fun VB.initViews() {}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)_binding?.initViews()}override fun onDestroyView() {super.onDestroyView()_binding = null}/*** 生成ViewBinding*/private fun generateViewBinding(rootView: ViewGroup?) {val type = this::class.java.genericSuperclass as? ParameterizedType ?: returnval vbClazz = type.actualTypeArguments.find {// 找到泛型声明为 实现了 ViewBinding接口的类型(it as Class<*>).genericInterfaces[0] == ViewBinding::class.java} as? Class<*> ?: returnval method = vbClazz.getMethod("inflate",LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java)_binding = method.invoke(null, layoutInflater, rootView, false) as VB}
}
3.3 Adapter
ViewHolder:
class BaseViewHolder<VB : ViewBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root)
Adapter:
abstract class ViewBindingAdapter<VB : ViewBinding> : RecyclerView.Adapter<BaseViewHolder<VB>>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<VB> {generateViewBinding(parent)?.let {return BaseViewHolder(it)} ?: TODO("Not yet implemented")}private fun generateViewBinding(parent: ViewGroup): VB? {val type = this::class.java.genericSuperclass as? ParameterizedType ?: return nullval vbClazz = type.actualTypeArguments.find {// 找到泛型声明为 实现了 ViewBinding接口的类型(it as Class<*>).genericInterfaces[0] == ViewBinding::class.java} as? Class<*> ?: return nullval layoutInflater = LayoutInflater.from(parent.context)val method = vbClazz.getMethod("inflate",LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java)return method.invoke(null, layoutInflater, parent, false) as VB}
}
相关文章:
ViewBinding使用入门
ViewBinding 参考资料: 新技术 ViewBinding 最佳实践 & 原理击穿 更多 ViewBinding 的封装思路 1. kotlin-android-extensions(KAE) 的问题 根据Google官方的说法, KAE存在以下问题: 污染全局命名空间不能暴露可空性信息仅支持Kotlin代码 kotlin在1.4.20中 开始废弃这…...
Retrofit源码分析实践(七)【Retrofit ConvertFactory的功能实现】
Retrofit源码分析&实践系列文章目录 Retrofit源码分析&实践(一)【从使用入手分析源码】Retrofit源码分析&实践(二)【Retrofit 免费的api测试工具引入】Retrofit源码分析&实践(三)【Retrofit 代码框架搭建】Retrofit源码分析&实践(四)【Retrofit 实…...
介电常数常用测量方法综述
张扬1,徐尚志1,赵文晖2,龚增2,赵晓群1 1同济大学,上海 2上海市计量测试技术研究院,上海 在设计电路、天线、电容器等过程中经常会涉及所用材料的介电常数, 所以深入了解介电常数的相关概念对实际工作有重…...
重生之我是赏金猎人(三)-SRC漏洞挖掘-强行多次FUZZ发现某厂商SSRF到redis密码喷洒批量反弹Shell
0x00 前言 https://github.com/J0o1ey/BountyHunterInChina 欢迎大佬们点个star 最近BugBounty挖了不少,但大多数都是有手就行的漏洞,需要动脑子的实属罕见 而今天就遇到了一个非常好的案例,故作此文 0x01 对目录批量FUZZ,发…...
学会分享,学会生活,分享5款简单易用的软件。
分享是一种博爱的心境,学会分享,就学会了生活。 1.在线图片编辑工具——佐糖 佐糖是一款在线免费图片编辑工具,采用AI人工智能技术,自动识别图片,支持一键抠图,更换背景,移除水印等。另外还提…...
Redux 与 Vuex 的区别总结
Redux 工作流程 首先,用户(通过 view)发送 Action,发送方式就用到了 dispatch 方法。然后,Store 自动调用 Reducer,并传入俩个参数,当前 State 和 收到的 Action。而 Reducer 会返回新的 State。最后,Store 根据接收到的 State,判断是否发生变化。一旦发生变化,Store…...
QT(15)- QFile
1 函数 1.1 copy bool QFile::copy(const QString &newName) QFile::copy(const QString &newName) 是 Qt 中用于复制文件的函数,将 fileName() 所指向的文件复制到 newName 指定的新位置。 在复制文件之前,源文件会先被关闭。如果被复制的文…...
GaiaX开源解读 | 表达式作为逻辑动态化的基础,我们是如何设计的
GaiaX跨端模板引擎,是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案,其核心优势是性能、稳定和易用。本系列文章《GaiaX开源解读》,带大家看看过去三年GaiaX的发展过程。 前言 GaiaX【https://github.com/alibaba/GaiaX】是由优酷应…...
python中adb shell相关操作
1、python 实现adb交互,进入adb shell后,如何再发送消息 os.popen("adb -s 192.168.1.100:5555 shell \"dmesg > /data/dmesg.log\"")进入进入adb shell,在执行 dmesg > /data/dmesg.log 2、python(或BAT脚本)自…...
python 之 资源使用与控制 resource模块
一、背景 2021年做可信计算时,由于甲方给的CPU利用率不能不能超过20%; 目的:我们的程序部署甲方服务器上不能阻碍其甲方服务的正常运行 我们的程序在CPU超过20%时,可以休眠几秒后继续运行 此时需要检测控制服务器的CPU资源使用信…...
蓝库云|8项关键让你看透企业「数字转型」,零代码是惊喜
各行各业都要面对的多方竞争力及不断上涨的经营成本,以及随着时代的发展,有不少企业纷纷推动数字化转型,考虑藉着应用现代化的数据和科技工具的结合,协助企业创造新的营运模式及收入来源,以提升自动化效率、优化客户体…...
(五)、编辑页面-发布长文-富文本编辑【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】
1,edit页面 1.1 新建edit页面 1.2 从本地相册选择图片或使用相机拍照。 uni.chooseImage(OBJECT) 1.3 直接上传文件到云存储。 uploadFile(Object object) 1.4 从富文本编辑器获取编辑器内容 editorContext.getContents(OBJECT) 首页富文本编辑器初始化完成时…...
你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式
你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式😎前言🙌大小端介绍🙌什么大端小端呢?:大小端存储的标准定义:大端和小端存在的意义经典的面试题目🙌总结撒花💞&a…...
从零开始的数模(二十六)单因素方差分析
目录 一、概念 1.1相关概念 1.2用途 1.3数据要求:独立性/正态性/方差齐性 1.4步骤 编辑1.5专业名词 二、基于python的单因素方差分析 2.2单因素方差分析的作用 一、概念 1.1相关概念 单因素方差分析是一种常用的统计分析方法,它用于比较一个因…...
C++变量类型
目录 一、c中的变量定义 二、c中的变量声明 三、c中的左值和右值 一、c中的变量定义 变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。 变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示&…...
win10 安装 vs2015(社区版本)以及opencv-4.5.5
一、下载vs2015以及opencv-4.5.5从https://msdn.itellyou.cn/ 网站下载vs2015(社区版本)从https://opencv.org/releases/网站下载opencv-4.5.5二、安装vs2015和opencv-4.5.5解压后双击exe安装文件,完成安装(默认)双击下…...
867. 转置矩阵
给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。示例 1:输入:matrix [[1,2,3],[4,5,6],[7,8,9]]输出:[[1,4,7],[2,5,8],[3,6,9]]示例 2&a…...
Datawahle组队学习——妙趣横生大数据 Day1
妙趣横生大数据 Day1[妙趣横生大数据 Juicy Big Data](https://datawhalechina.github.io/juicy-bigdata/#/?id妙趣横生大数据-juicy-big-data)一、大数据概述大数据——第三次信息化浪潮大数据概念大数据应用大数据关键技术二、Hadoop背景介绍特性项目架构实验1. 准备工作2. …...
网友眼中越老越吃香的行业,果然是风向变了!
越老越吃香的行业,一直都是被热议的话题。对于年轻人来说,找到一个适合自己的并且具有前景的工作,不是一件容易的事情。 最近,看到有人在平台上问相关的问题,本着认真看一看的态度点进去,却差点被热评第一…...
为什么时间序列预测这么难?本文将给你答案
机器学习和深度学习已越来越多应用在时序预测中。ARIMA 或指数平滑等经典预测方法正在被 XGBoost、高斯过程或深度学习等机器学习回归算法所取代。 尽管时序模型越来越复杂,但人们对时序模型的性能表示怀疑。有研究表明,复杂的时序模型并不一定会比时序…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
