利用 ViewBinding 和反射封装的基类,从此再也不用 findViewById 了

2023-11-15

code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群

作者:段颖超丨乐拼
链接:https://www.jianshu.com/p/ea395a83c666
声明:本文已获段颖超丨乐拼授权发表,转发等请联系原作者授权

今天从Google公众号了解到关于ViewBinding的相关文章,赶上手头项目正在做优化,于是结合反射封装了BaseActivity和BaseFragment,记录下来同时和大家一起探讨学习。先简单介绍下ViewBinding:

从 Android Studio 3.6 开始,ViewBinding能够通过生成绑定对象来替代 findViewById,从而可以帮你简化代码,并且从 findViewById 的模版代码中解脱出来。ViewBinding的主要优点是所有绑定类都是由Gradle插件生成的,因此它对构建时间没有影响,并且具有编译时安全性。

ViewBinding与DataBinding的区别:

DataBinding 仅处理使用代码创建的数据绑定布局;ViewBinding 不支持布局变量或布局表达式,因此它不能用于在 XML 中将布局与数据绑定。

ViewBinding相较ButterKnife、Kotlin Android Extensions的几点优势:

目前Android开发中完成View映射的方法主要有 findViewById、 ButterKnife, 如果使用kotlin的话还可以使用Kotlin Android Extensions。

偷个懒,直接引用下其它文章中的描述:

Type safety:findViewById, ButterKnife 均存在类型转换问题,例如不小心将一个TextView错误的赋值给一个Button变量,都会报错,这一错误很容易出现,关键在错误还出现在运行时,而不是编译时!而ViewBinding中,产生的binding类中的属性是依据XML layout文件生成的,所以类型不会错,生成的时候已经处理好了。
Null safety: findViewById, ButterKnife与Kotlin Android Extensions 均存在Null不安全问题。这个什么意思呢?就是在我们访问那个View的时候它不存在。为什么会出现这种情况呢?例如不小心使用了错误的Id,或者访问的时候那个view还不存在。使用了错误Id这个估计大家都有此类经历,但是访问时候那个view不存在怎么理解呢?例如我们在手机横屏和竖屏的时候分别使用一套XML layout文件,假设横屏中包含了一个竖屏中没有的view,那么在屏幕从横屏旋转到竖屏的时候,NullPointer问题就出现了。而ViewBinding中, 产生的binding类中的属性是依据XML layout文件生成的,所以Id不会错。而且其将仅存在某一个配置下的layout文件的那些view对应的字段标记为@Nullable,而且,生成类中还会很贴心的给你加上详细的注释。这一切都是为了提醒程序员,注意对这个view特别处理,它在某些情况下为Null。
简洁优雅:将绑定view的模板代码自动生成到了其他类中,使controlor类(Activity,Fragment)更加清晰了。

原文链接:https://blog.csdn.net/ShuSheng0007/article/details/103246642

ViewBinding的常规使用:

  1. 在 build.gradle 中开启视图绑定 开启视图绑定无须引入额外依赖,从 Android Studio 3.6 开始,视图绑定将会内建于 Android Gradle 插件中。需要打开视图绑定的话,只需要在 build.gradle 文件中配置 viewBinding 选项:

// 需要 Android Gradle Plugin 3.6.0
android {
	viewBinding {
		enabled =true
	}
}

在 Android Studio 4.0 中,viewBinding 变成属性被整合到了 buildFeatures 选项中,所以配置要改成:

//Android Studio 4.0
android{
	buildFeatures{
		viewBinding=true
	}
}

配置完成后,视图绑定就会根据现有的 XML 文件,为 Module 内所有的布局文件生成绑定对象。无须修改原有布局的 XML 文件,视图绑定将根据你现有的布局自动完成所有工作。你可以在任何需要填充布局的地方使用绑定对象,比如 Fragment、Activity、甚至是 RecyclerView Adapter(或者说是 ViewHolder 中)。

  1. 在 Activity 中使用视图绑定 假如你有一个布局文件名叫 activity_my.xml,其中包含了一个按钮和两个文本视图。视图绑定会为这个布局生成一个名叫 ActivityMyBinding 的类,布局文件中所有拥有 id 的视图,都会在这个类中有一个对应的属性:

overridefunonCreate(savedInstanceState:Bundle?){
	super.onCreate(savedInstanceState)
	val binding = ActivityMyBinding.inflate(layoutInflater)
	binding.title.text ="Hello"
	binding.subtext.text ="World"
	binding.button.setOnClickListener {
		/* ... */
	}
	setContentView(binding.root)
}
  1. 在 Fragment,RecyclerView Adapter等的使用可参考文章:

https://blog.csdn.net/fly_with_24/article/details/104337067

————————————————

BaseActivity的封装和使用:

abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
    lateinit var binding: VB
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //利用反射,调用指定ViewBinding中的inflate方法填充视图
        val type = javaClass.genericSuperclass
        if (type is ParameterizedType) {
            val clazz = type.actualTypeArguments[0] as Class<VB>
            val method = clazz.getMethod("inflate", LayoutInflater::class.java)
            binding = method.invoke(null, layoutInflater) as VB
            setContentView(binding.root)
        }

        init()
    }

    abstract fun init()
}

此时,我们的Activity的使用就比较简单了:

class MyActivity : BaseActivity<ActivityMyBinding>() {
    override fun init() {
        binding.title.text ="Hello"
        binding.subtext.text ="World"
        binding.button.setOnClickListener {
            /* ... */
        }
        /* ... */
    }
}

BaseFragment的封装和使用:

abstract class BaseFragment<VB : ViewBinding> : Fragment() {
    private var _binding : VB? = null
    val binding :VB get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        //利用反射,调用指定ViewBinding中的inflate方法填充视图
        val type = javaClass.genericSuperclass
        val clazz = (type as ParameterizedType).actualTypeArguments[0] as Class<VB>
        val method = clazz.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
        _binding = method.invoke(null, layoutInflater, container, false) as VB
        return _binding!!.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        init()
    }

    abstract fun init()

    override fun onDestroyView() {
        _binding = null
        super.onDestroyView()
    }
}

接着在我们的Fragment使用吧!

class MyFragment : BaseFragment<FragmentMyBinding>() {
    override fun init() {
        binding.title.text ="Hello"
        binding.subtext.text ="World"
        binding.button.setOnClickListener {
            /* ... */
        }
        /* ... */
    }
}

哈哈,世界清净了!!!

本文仅作为基类封装的参考,未考虑其它因素,欢迎各位给出己见,共同进步。

写作不易,如有帮助,还望点个赞。

相关阅读

Flutter 添加到现有项目
JetPack + 单 Activity 的一些思路
Android app后台回到前台时的监听
三年 Android 经验面经
Android Jetpack 最佳开发姿势

如果你有写博客的好习惯

欢迎投稿

点个在看,小生感恩❤️

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

利用 ViewBinding 和反射封装的基类,从此再也不用 findViewById 了 的相关文章

  • stm32相关知识笔记

    keil公司是为51 arm芯片提供软件开发IDE的公司 2005年被ARM收购 Keil MDK ARM是美国Keil软件公司 现已被ARM公司收购 出品的支持ARM微控制器的一款IDE 集成开发环境 MDK ARM包含了工业标准的Kei
  • Python3,使用openpyxl进行excel数据对比,反手一个赞。

    openpyxl技能 1 引言 2 代码实战 2 1 安装 2 2 代码实战 2 2 1 思路 2 2 2 代码示例 3 总结 1 引言 小屌丝 鱼哥 我最近在对搞数据对比 你有什么便捷的方法 小鱼 斗胆问一句 数据量多少 小屌丝 不多不多
  • Activiti启动流程实例,runtimeService.startProcessInstanceByKey

    启动流程实例 添加进businessKey 本质 act ru execution表中的businessKey的字段要存入业务标识 public class BusinessKeyAdd public static void main St
  • oVirt 4.4.10三节点超融合集群安装配置及集群扩容(一)

    环境 oVrit版本 4 4 10 oVirt image https mirrors aliyun com ovirt ovirt 4 4 iso ovirt node ng installer 4 4 10 2022030308 el8
  • JAVA中的反射机制以及在Spring中的应用

    文章目录 一 反射机制 二 反射机制的使用 Class类 三 为什么要使用反射 3 1 静态编译 3 2 动态编译 3 3 反射的好处 3 4 反射的缺点 四 Spring IOC中的体现 4 1 Spring IOC的实现方式 4 2 代
  • linux内核知识图谱

    根据 深入linux内核架构 linux内核设计与实现 深入理解linux内核 得出linux内核的大类知识模块 进行后续主题式学习
  • 如何在react中使用websocket

    一 如何引用websocket npm install save react websocket 二 在组件中如何使用 1 先封装一个websocket组件 import React from react import Websocket
  • 在HTML页面中引用Markdown编辑器(Editor.md)

    目录 1 下载Ediotor md 2 引入Ediotor md 3 确定Ediotor md在哪里显示 最近写博客项目 用到了Markdown编辑器 这里介绍一款国内好用的Markdown编辑器 Editor md 下面介绍一下该编辑器以
  • ElementUI的表单效验问题 (一个页面两个form(数据相似))

    两个form 注意 两个表单必须绑定不同的 key key为字符串 否则 vue看两个表单数据大致相同就会将其上面的复用 导致效验不生效 rules
  • 论述GIS当前现状以及未来的发展前景

    GIS是空间技术和信息技术的交叉学科 相关领域的研究热点都有可能成为GIS的发展趋势 GIS的技术环节无外乎数据获取 数据分析 数据呈现三个方面 从近年的发展情况看 GIS可能在这三个方面都有着激动人心的前景 一 数据获取 数据是GIS的基
  • 警告:检测到时钟错误。您的创建可能是不完整的。

    问题 make 2 Warning File CMakeFiles MultiCol SLAM dir depend make has modification time 24688 s in the future make 2 警告 检测
  • 模式识别 - 名词解释整理

    模式识别 模式识别是指把对象根据其特征归到若干类别中适当的一类 模式识别也称为模式分类 模式 模式是指因素间存在确定性或随机性规律的对象 过程或事件的集合 识别 识别就是把对象分门别类地认出来 样本 sample 所研究对象的一个个体 样本
  • Python3中参数*args和**kwargs介绍

    在Python中 我们可以使用两种特殊符号将可变数量的参数传递给函数 args和 kwargs 你可以使用任何单词代替args和kwargs 但通常做法是使用args和kwargs args允许函数接受任意数量的位置参数 positiona
  • vue学习-01vue入门

    Vue官网地址 https cn vuejs org Vue介绍 Vue 读音 vju 类似于 view 是一套用于构建用户界面的渐进式框架 与其它大型框架不同的是 Vue 被设计为可以自底向上逐层应用 Vue 的核心库只关注视图层 不仅易
  • C++模拟鼠标移动及单击实现代码

    摘要 本文分享了如何通过代码实现重复点击按钮 要实现该功能有个关键点需要注意 许多软件的按钮不是一个窗口 所以无法通过枚举窗口或者查找子窗口来定位按钮 本文通过直接定位按钮位置来避免这个问题 该程序的使用方法 管理员运行程序 移动鼠标指针到
  • C++ 预处理器

    http www runoob com cplusplus cpp preprocessor html
  • 虚拟专用网之L2TP协议介绍

    目录 L2TP简介 L2TP构建图解 L2TP建立及拆除流程 L2TP隧道的建立 L2TP会话的建立 L2TP隧道和会话维护和拆除流程 L2TP协议栈结构及数据包的封装过程 L2TP隧道和会话的验证过程 L2TP和PPTP的区别 L2TP简
  • z字形扫描

    z字形扫描 类别 数组 时间限制 1S 内存限制 256Kb 问题描述 在图像编码的算法中 需要将一个给定的方形矩阵进行Z字形扫描 Zigzag Scan 给定一个m n的矩阵 Z字形扫描的过程如下图所示 对于下面给出的4 4的矩阵 1 5
  • android studio从git上克隆项目显示the directory already exists and it is not empty

    英文的意思能看懂 文件夹已存在并且不为空 但是网上百度了一下貌似没有完完整整是这句话的问题 我还纳闷怎么克隆不下来 我是想把项目克隆下来到workspace里面 workspace里面本来就还有其他项目在 原来克隆操作不会帮你生成跟目录 你
  • Android 10.0 系统settings详情页 卸载修改为停止,禁止卸载app功能实现

    1 概述 在10 0的系统rom定制化功能的开发过程中 在一些系统预安装的app中 在Launcher3中可以通过拖拽然后卸载 这个限制卸载可以在前面的博客中禁止卸载这些预安装的app 然后就需要在系统Settings详情页来禁止app的卸

随机推荐

  • C语言 用户输入运算数和四则运算符,输出计算结果

    用C语言中简单的语句可以实现四则运算 1 if语句 include
  • 翻译 第11章 of IEEE Std 1666-2011 IEEE Standard for Standard SystemC Language Reference Manual

    11 TLM 2 0 core interfaces 11 TLM 2 0 核心接口 In addition to the core interfaces from TLM 1 TLM 2 0 adds blocking and non b
  • 如何把笔记本做台式机的副屏(一套键鼠控制两台电脑)

    通过一套键鼠控制两台电脑 前提 安装所需的软件 一 简介 二 安装 2 1 小技巧 前提 两台电脑在同一个局域网内 并且均为windows操作系统 例如两台电脑链接的同一个WIFI 或者笔记本无线连接路由 台式机插网线链接路由 只有在同一个
  • 史上最全排序算法全面总结

    考察点 在信息学奥赛初赛中对于排序算法的考察主要体现在以下几方面 1 时间复杂度 2 稳定性 3 最坏情况下移动次数 4 移动次数与关键字顺序关系 先看熟记知识点 1 关于稳定性 假定在待排序的记录序列中 存在多个具有相同的关键字的记录 若
  • 指针空间的申请和释放

    http blog csdn net netanimals article details 6530787
  • 若依跨域解决

    发现接口取消权限校验之后 跨域调用还是失败了 若依本身有跨域配置 注释掉换为新的 若依原跨域配置 ResourcesConfig 中 跨域配置 Bean public CorsFilter corsFilter CorsConfigurat
  • matlab中常用符号

    在使用MATLAB的过程中 经常需要对输出图形中的变量进行标注 其中经常遇到的难题就是如何标注各种上标 下标 斜体 黑体 箭头 上圆圈 正负号等特殊符号 以及如何标注特殊的数学符号 这里第一机电网给大家总结一下 希望对大家有用 一 MATL
  • 奥林巴斯新微单E-M5II曝光:合金机身可防水

    通常单反相机是专业摄影师的最佳工具 但是对于普通消费者来说 既要拥有专业的图像质量 又不想负担单反相机沉重的质量 就成为了基本的要求 因此 微单相机就在这种情况下应运而生 如果你还没决定好选择哪一款微单 那么奥林巴斯即将推出的这款OM D
  • Android APP性能及专项测试

    Android篇 1 性能测试 Android性能测试分为两类 1 一类为rom版本 系统 的性能测试 2 一类为应用app的性能测试 Android的app性能测试包括的测试项比如 1 资源消耗 2 内存泄露 3 电量功耗 4 耗时 5
  • 【C++ 进阶】继承

    一 继承的定义格式 基类又叫父类 派生类又叫子类 二 继承方式 继承方式分为三种 1 public继承 2 protected继承 3 private继承 基类成员与继承方式的关系共有9种 见下表 虽然说是有9种 但其实最常用的还是红框里的
  • 随心所欲Do whatever you want——Minecraft

    Minecraft是一款沙盒类电子游戏 开创者是马库斯 阿列克谢 泊松 由微软旗下Mojang Studios维护 从2017年开始 中国版 我的世界 由网易游戏代理 目标 Minecraft着重于让玩家去探索 交互 并且改变一个由一立方米
  • Github使用学习笔记(二)

    第二节任务 如何把我在本地上的工程上传到github上已经建好的仓库中 一 在本地目录下创建我的版本库 mkdir learngit cd learngit git init ls ah 首先创建一个空目录 目录名为learngit 之后进
  • 【华为OD】

    目录 一 题目描述 二 输入描述 三 输出描述 备注 用例 四 题目解析 五 Java玩法 六 JavaScript玩法 一 题目描述 一个图像有 n 个像素点 存储在一个长度为 n 的数组 img 里 每个像素点的取值范围 0 255 的
  • 网站流量统计

    常使用web服务器的朋友大都了解 一般的web server有两部分日志 一是运行中的日志 它主要记录运行的一些信息 尤其是一些异常错误日志信息 二是访问日志信息 它记录的访问的时间 IP 访问的资料等相关信息 现在我来和大家介绍一下利用t
  • 高级定时器 tim1 tim8 一般中断配置,以防以后忘记

    void Timer8 Init void TIM TimeBaseInitTypeDef TIM TimeBaseStructure NVIC InitTypeDef NVIC InitStructure RCC APB2PeriphCl
  • C++设计模式——单例模式 (一)

    单例模式 一个类只能创建一个对象 单例模式是C 中常用的一种设计模式 熟悉Qt的朋友肯定清楚QApplication实际也是采用的单例模式 并且为用户提供了一个全局的指针对象 qApp 我们先看看Qt中对于单例的实现 define qApp
  • Android NDK是什么

    官方给出的答案 Android NDK 是一套允许您使用原生代码语言 例如 C 和 C 实现部分应用的工具集 在开发某些类型应用时 这有助于您重复使用以这些语言编写的代码库 深入的学习 https developer android goo
  • 13 款炫酷的 MySQL 可视化管理工具!好用到爆!!

    MySQL 的管理维护工具非常多 除了系统自带的命令行管理工具之外 还有许多其他的图形化管理工具 工具好用是一方面 个人的使用习惯也很重要 这里介绍 13 款 MySQL 图形化管理工具 供大家参考 1 DBeaver DBeaver 是一
  • 分数运算(类+构造)

    题目描述 用C 定义和实现一个分数类 并根据要求完成分数对象的运用 分数类包含分子和分母两个属性 操作包括 各属性的get方法 构造函数 初始化分子分母 相加运算 该运算接收两个分数对象的分子和分母 然后进行分数相加 结果保存在自己的分子和
  • 利用 ViewBinding 和反射封装的基类,从此再也不用 findViewById 了

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者 段颖超丨乐拼链接 https www jianshu com p ea395a83c666声明 本文已获段颖超丨乐拼授权发表 转发等请联系原作者授权 今