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、高斯过程或深度学习等机器学习回归算法所取代。 尽管时序模型越来越复杂,但人们对时序模型的性能表示怀疑。有研究表明,复杂的时序模型并不一定会比时序…...
PCB数据处理利器:从安装到实战的全方位指南
PCB数据处理利器:从安装到实战的全方位指南 【免费下载链接】pcb-tools Tools to work with PCB data (Gerber, Excellon, NC files) using Python. 项目地址: https://gitcode.com/gh_mirrors/pc/pcb-tools 1. 项目价值解析 PCB Tools作为一款专注于印制电…...
2025夏季技术实习「抢位战」:3步解锁2500+优质机会(附避坑指南)[特殊字符]
2025夏季技术实习「抢位战」:3步解锁2500优质机会(附避坑指南)🔥 【免费下载链接】Summer2026-Internships 2025年夏季技术实习机会集合! 项目地址: https://gitcode.com/GitHub_Trending/su/Summer2026-Internships…...
不用下载IDE!浏览器直接练Python二级考题的宝藏网站测评
浏览器直通Python二级考场:零配置备考实战指南 距离全国计算机二级Python考试还有30天,小张的笔记本电脑却突然罢工。维修店报价让他望而却步,而图书馆公共电脑禁止安装软件的规定更让他雪上加霜。这种困境并非个例——据教育技术协会2024年…...
RWKV7-1.5B-g1a一文详解:轻量中文对话与文案续写实战
RWKV7-1.5B-g1a一文详解:轻量中文对话与文案续写实战 1. 模型简介 rwkv7-1.5B-g1a 是一款基于RWKV-7架构的多语言文本生成模型,特别适合中文场景下的轻量级应用。这个1.5B参数的模型在保持较小体积的同时,能够出色完成基础问答、文案续写、简…...
s2-pro GPU算力适配实战:显存优化部署让语音合成延迟降低40%
s2-pro GPU算力适配实战:显存优化部署让语音合成延迟降低40% 1. 专业语音合成新选择 s2-pro是Fish Audio开源的专业级语音合成模型镜像,它让高质量的文本转语音变得触手可及。与普通语音合成工具不同,s2-pro支持通过参考音频复用音色&#…...
毕设程序java师生交流系统的设计与实现 基于Java的师生互动教学平台设计与实现 基于SpringBoot的在线教育沟通系统开发
毕设程序java师生交流系统的设计与实现343xt8ar(配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着信息技术的飞速发展,传统的教育模式正在经历一场深刻的变革。互联…...
RS485接口EMC设计与防护电路实现
RS485接口电路的EMC设计与工程实现1. 项目概述1.1 RS485接口的EMC挑战RS485作为工业通信标准接口,其典型应用场景中信号走线常与电源线、功率信号线混合布线,导致以下EMC问题:共模干扰通过长距离传输线耦合浪涌脉冲对接口电路的冲击损坏高频噪…...
STM32从入门到实战:两周速成指南
STM32快速入门指南:从零基础到项目实战1. 项目概述1.1 STM32与8051的对比分析对于已经掌握8051和C语言的开发者而言,STM32的学习曲线并不陡峭。关键在于理解何时需要从8051迁移到STM32平台:计算能力需求:当8051的主频无法满足复杂…...
Linux内核构建系统:Makefile、Kconfig与.config解析
1. Linux内核构建系统核心组件解析1.1 内核构建系统概述Linux内核作为复杂的开源项目,其构建系统由三个关键组件构成:Makefile、Kconfig和.config文件。这三个组件协同工作,构成了内核模块化构建的基础架构。1.1.1 组件类比关系Kconfig&#…...
EmbeddingGemma-300m在Mathtype公式的语义理解中的应用
EmbeddingGemma-300m在Mathtype公式的语义理解中的应用 1. 引言 数学公式的语义理解一直是自然语言处理领域的挑战性任务。传统的文本嵌入模型在处理复杂的数学表达式时往往力不从心,无法准确捕捉公式背后的数学含义和逻辑关系。EmbeddingGemma-300m作为Google最新…...
