当前位置: 首页 > news >正文

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中只用

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Activity 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. 将根视图传递到 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中使用

  1. 调用生成的绑定类中包含的静态 inflate() 方法。此操作会创建该绑定类的实例以供 Fragment 使用。
  2. 通过调用 getRoot() 方法或使用 Kotlin 属性语法获取对根视图的引用。
  3. 从 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的代码:

  1. 删除include标签上的id属性
  2. 在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&#xff0c;徐尚志1&#xff0c;赵文晖2&#xff0c;龚增2&#xff0c;赵晓群1 1同济大学&#xff0c;上海 2上海市计量测试技术研究院&#xff0c;上海 在设计电路、天线、电容器等过程中经常会涉及所用材料的介电常数, 所以深入了解介电常数的相关概念对实际工作有重…...

重生之我是赏金猎人(三)-SRC漏洞挖掘-强行多次FUZZ发现某厂商SSRF到redis密码喷洒批量反弹Shell

0x00 前言 https://github.com/J0o1ey/BountyHunterInChina 欢迎大佬们点个star 最近BugBounty挖了不少&#xff0c;但大多数都是有手就行的漏洞&#xff0c;需要动脑子的实属罕见 而今天就遇到了一个非常好的案例&#xff0c;故作此文 0x01 对目录批量FUZZ&#xff0c;发…...

学会分享,学会生活,分享5款简单易用的软件。

分享是一种博爱的心境&#xff0c;学会分享&#xff0c;就学会了生活。 1.在线图片编辑工具——佐糖 佐糖是一款在线免费图片编辑工具&#xff0c;采用AI人工智能技术&#xff0c;自动识别图片&#xff0c;支持一键抠图&#xff0c;更换背景&#xff0c;移除水印等。另外还提…...

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 中用于复制文件的函数&#xff0c;将 fileName() 所指向的文件复制到 newName 指定的新位置。 在复制文件之前&#xff0c;源文件会先被关闭。如果被复制的文…...

GaiaX开源解读 | 表达式作为逻辑动态化的基础,我们是如何设计的

GaiaX跨端模板引擎&#xff0c;是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案&#xff0c;其核心优势是性能、稳定和易用。本系列文章《GaiaX开源解读》&#xff0c;带大家看看过去三年GaiaX的发展过程。 前言 GaiaX【https://github.com/alibaba/GaiaX】是由优酷应…...

python中adb shell相关操作

1、python 实现adb交互&#xff0c;进入adb shell后&#xff0c;如何再发送消息 os.popen("adb -s 192.168.1.100:5555 shell \"dmesg > /data/dmesg.log\"")进入进入adb shell&#xff0c;在执行 dmesg > /data/dmesg.log 2、python(或BAT脚本)自…...

python 之 资源使用与控制 resource模块

一、背景 2021年做可信计算时&#xff0c;由于甲方给的CPU利用率不能不能超过20%&#xff1b; 目的&#xff1a;我们的程序部署甲方服务器上不能阻碍其甲方服务的正常运行 我们的程序在CPU超过20%时&#xff0c;可以休眠几秒后继续运行 此时需要检测控制服务器的CPU资源使用信…...

蓝库云|8项关键让你看透企业「数字转型」,零代码是惊喜

各行各业都要面对的多方竞争力及不断上涨的经营成本&#xff0c;以及随着时代的发展&#xff0c;有不少企业纷纷推动数字化转型&#xff0c;考虑藉着应用现代化的数据和科技工具的结合&#xff0c;协助企业创造新的营运模式及收入来源&#xff0c;以提升自动化效率、优化客户体…...

(五)、编辑页面-发布长文-富文本编辑【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1&#xff0c;edit页面 1.1 新建edit页面 1.2 从本地相册选择图片或使用相机拍照。 uni.chooseImage(OBJECT) 1.3 直接上传文件到云存储。 uploadFile(Object object) 1.4 从富文本编辑器获取编辑器内容 editorContext.getContents(OBJECT) 首页富文本编辑器初始化完成时…...

你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式

你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式&#x1f60e;前言&#x1f64c;大小端介绍&#x1f64c;什么大端小端呢&#xff1f;&#xff1a;大小端存储的标准定义&#xff1a;大端和小端存在的意义经典的面试题目&#x1f64c;总结撒花&#x1f49e;&a…...

从零开始的数模(二十六)单因素方差分析

目录 一、概念 1.1相关概念 1.2用途 1.3数据要求&#xff1a;独立性/正态性/方差齐性 1.4步骤 ​编辑1.5专业名词 二、基于python的单因素方差分析 2.2单因素方差分析的作用 一、概念 1.1相关概念 单因素方差分析是一种常用的统计分析方法&#xff0c;它用于比较一个因…...

C++变量类型

目录 一、c中的变量定义 二、c中的变量声明 三、c中的左值和右值 一、c中的变量定义 变量定义就是告诉编译器在何处创建变量的存储&#xff0c;以及如何创建变量的存储。 变量定义指定一个数据类型&#xff0c;并包含了该类型的一个或多个变量的列表&#xff0c;如下所示&…...

win10 安装 vs2015(社区版本)以及opencv-4.5.5

一、下载vs2015以及opencv-4.5.5从https://msdn.itellyou.cn/ 网站下载vs2015&#xff08;社区版本&#xff09;从https://opencv.org/releases/网站下载opencv-4.5.5二、安装vs2015和opencv-4.5.5解压后双击exe安装文件&#xff0c;完成安装&#xff08;默认&#xff09;双击下…...

867. 转置矩阵

给你一个二维整数数组 matrix&#xff0c; 返回 matrix 的 转置矩阵 。矩阵的 转置 是指将矩阵的主对角线翻转&#xff0c;交换矩阵的行索引与列索引。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]输出&#xff1a;[[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. …...

网友眼中越老越吃香的行业,果然是风向变了!

越老越吃香的行业&#xff0c;一直都是被热议的话题。对于年轻人来说&#xff0c;找到一个适合自己的并且具有前景的工作&#xff0c;不是一件容易的事情。 最近&#xff0c;看到有人在平台上问相关的问题&#xff0c;本着认真看一看的态度点进去&#xff0c;却差点被热评第一…...

为什么时间序列预测这么难?本文将给你答案

机器学习和深度学习已越来越多应用在时序预测中。ARIMA 或指数平滑等经典预测方法正在被 XGBoost、高斯过程或深度学习等机器学习回归算法所取代。 尽管时序模型越来越复杂&#xff0c;但人们对时序模型的性能表示怀疑。有研究表明&#xff0c;复杂的时序模型并不一定会比时序…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...