将视图转为image_使用视图绑定替代 findViewById
从 Android Studio 3.6 开始,视图绑定能够通过生成绑定对象来替代 findViewById,从而可以帮您简化代码、移除 bug,并且从 findViewById 的模版代码中解脱出来。
本文梗概
- 在 build.gradle 中就可以方便快捷地开启视图绑定且无须额外引入依赖库
- 视图绑定会为 Module 中的每一个布局文件生成一个绑定对象 (activity_awesome.xml → ActivityAwesomeBinding.java)
- 布局文件中每一个带有 id 的视图都会在绑定对象中有一个对应的属性,这个属性将拥有正确的类型,并且空安全
- 视图绑定完美支持 Java 和 Kotlin 编程语言
更多详细内容可以从视频:使用视图绑定替代 findViewById 中获取。
在 build.gradle 中开启视图绑定
开启视图绑定无须引入额外依赖,从 Android Studio 3.6 开始,视图绑定将会内建于 Android Gradle 插件中。需要打开视图绑定的话,只需要在 build.gradle 文件中配置 viewBinding 选项:
// 需要 Android Gradle Plugin 3.6.0android { viewBinding { enabled = true }}
在 Android Studio 4.0 中,viewBinding 变成属性被整合到了 buildFeatures 选项中,所以配置要改成:
// Android Studio 4.0android { buildFeatures { viewBinding = true }}
配置完成后,视图绑定就会为所有布局文件自动生成对应的绑定类。无须修改原有布局的 XML 文件,视图绑定将根据您现有的布局自动完成所有工作。
视图绑定将会根据现有的 XML 文件,为 Module 内所有的布局文件生成绑定对象。
您可以在任何需要填充布局的地方使用绑定对象,比如 Fragment、Activity、甚至是 RecyclerView Adapter(或者说是 ViewHolder 中)。
在 Activity 中使用视图绑定
假如您有一个布局文件名叫 activity_awesome.xml,其中包含了一个按钮和两个文本视图。视图绑定会为这个布局生成一个名叫 ActivityAwesomeBinding 的类,布局文件中所有拥有 id 的视图,都会在这个类中有一个对应的属性:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = ActivityAwesomeBinding.inflate(layoutInflater) binding.title.text = "Hello" binding.subtext.text = "Concise, safe code" binding.button.setOnClickListener { /* ... */ } setContentView(binding.root)}
△ 在 Activity 中使用视图绑定
使用视图绑定时,无须再调用 findViewById 方法,只要直接调用绑定对象中的对应属性即可。
布局的根视图(无论有没有 id)都会自动生成一个名为 root 的属性。在 Activity 的 onCreate 方法中,要将 root 传入 setContentView 方法,从而让 Activity 可以使用绑定对象中的布局。
一个常见的错误用法是: 在开启了视图绑定的同时,依然在 setContentView(...) 中传入布局的 id 而不是绑定对象。这将造成同一布局被填充两次,同时监听器也会被添加到错误的布局对象中。
解决方案: 在 Activity 中使用视图绑定时,一定要将绑定对象的 root 属性传入 setContentView() 方法中。
使用绑定对象编写安全性更佳的代码
findViewById 是许多用户可见 bug 的来源: 我们很容易传入一个布局中根本不存在的 id,从而导致空指针异常而崩溃;由于此方法类型不安全,也很容易使人写出像 findViewById(R.id.image) 这样的,导致类型转换错误的代码。为了解决这些问题,视图绑定把 findViewById 替换成了更加简洁和安全的实现。
视图绑定有下面两个特性:
- 类型安全: 因为视图绑定总是会基于布局中的视图生成类型正确的属性。所以如果您在布局中放入了一个 TextView ,视图绑定就会暴露一个 TextView 类型的属性给您。
- 空安全: 视图绑定会检测某个视图是不是只在一些配置下存在,并依据结果生成带有 @Nullable 注解的属性。所以即使在多种配置下定义的布局文件,视图绑定依然能够保证空安全。
由于生成的绑定类是普通的 Java 类,并且其中添加了 Kotlin 友好的注解,所以 Java 和 Kotlin 都可以使用视图绑定。
视图绑定生成的代码是怎样的
如前文所说,视图绑定会生成一个包含替代 findViewById 功能的 Java 类。它会为 Module 下的每一个布局的 XML 文件生成一个对应的绑定对象,并根据源文件为其命名,比如 activity_awesome.xml 对应的绑定对象为 ActivityAwesomeBinding.java。
生成代码的逻辑被优化为,当您在 Android Studio 中编辑 XML 布局文件时,只会更新所修改布局对应的绑定对象。同时这些工作会在内存中运行,从而使这个过程可以迅速完成。这意味着您的修改会立即反映在绑定对象中,而无须等待或者重新构建工程。
Android Studio 被优化为可以在您编辑过 XML 布局文件后立即更新绑定对象。
让我们通过一个 示例 XML 布局 所生成的代码,来了解一下视图绑定究竟生成了什么。
public final class ActivityAwesomeBinding implements ViewBinding { @NonNull private final ConstraintLayout rootView; @NonNull public final Button button; @NonNull public final TextView subtext; @NonNull public final TextView title;
△ 视图绑定生成的属性。可以看到它们都是类型安全以及空安全的
视图绑定会根据每个拥有 id 的视图生成类型正确的属性。他也会为根布局生成 rootView 属性并通过 getRoot 暴露给您。视图绑定没有添加任何额外的逻辑,他只是把视图属性暴露给您,从而帮您在不使用 findViewById 的情况下也能调用它们。这样一来便保证了生成文件简洁性(当然也避免了拖慢构建速度)。
如果您正在使用 Kotlin,视图绑定的生成类也已经对互操作进行了优化。通过 @Nullable 和 @NonNull 注解的使用,Kolin 可以正确的将属性暴露为空安全类型。如果想要了解更多关于两种语言的互操作问题,请查阅文档: 在 Kotlin 中调用 Java。
private ActivityAwesomeBinding(@NonNull ConstraintLayout rootView, @NonNull Button button, @NonNull TextView subtext, @NonNull TextView title) { … } @NonNull public static ActivityAwesomeBinding inflate(@NonNull LayoutInflater inflater) { /* 编辑过: 移除了重载方法 inflate(inflater, parent, attachToParent) 的调用*/ View root = inflater.inflate(R.layout.activity_awesome, null, false); return bind(root); }
视图绑定会生成 inflate 方法作为生成一个绑定对象实例的主要方式。在 ActivityAwesomeBinding.java 中,视图绑定生成了一个只有一个参数的 inflate 方法,该方法通过将 parent 设定为空值来指定当前视图不会绑定到父视图中;视图绑定也暴露了一个有三个参数的 inflate 方法,来让您在需要的时候传入 parent 和 attachToParent 参数。
真正神奇的地方是 bind 方法的调用。这里会填充视图并绑定所有的属性,同时做一些错误检测并生成清晰的错误提示。
@NonNull public static ActivityAwesomeBinding bind(@NonNull View rootView) { /* 编辑: 简化代码 – 真实情况下生成的代码是一个优化过的版本 */ Button button = rootView.findViewById(R.id.button); TextView subtext = rootView.findViewById(R.id.subtext); TextView title = rootView.findViewById(R.id.title); if (button != null && subtext != null && title != null) { return new ActivityAwesomeBinding((ConstraintLayout) rootView, button, subtext, title); } throw new NullPointerException("Missing required view […]");}
△ 自动生成的 bind 方法的简化版本
bind 是绑定对象中最复杂的一个方法,它通过调用 findViewById 来绑定每个视图。既然编译器可以通过 XML 布局文件知道每个属性的类型和为空的可能性,那他就可以安全的调用 findViewById。
请注意,视图绑定生成的真正的 bind 方法要来的更长,并且其中使用了一个标记 break 语句来优化字节码,您可以查看 Jake Wharton 撰写的这篇文章 来了解更多优化有关的内容。在每个绑定对象中,都会暴露三个静态方法来创建绑定对象实例,下面是每个方法使用场景的简要说明:
- inflate(inflater) -- 在例如 Activity onCreate 方法里,这类没有父视图需要被传入的场合使用
- inflate(inflater, parent, attachToParent) -- 在 Fragment 或 RecyclerView Adapter (或者说 ViewHolder 中) ,这类您需要传递父级 ViewGroup 给绑定对象时使用。
- bind(rootView) -- 在您已经获得对应视图,并且只想通过视图绑定来避免使用 findViewById 时使用。这个方法在使用视图绑定改造和重构现有代码时非常有用。
对使用include标签引入的布局会发生什么影响
前面已经讲过,视图绑定会为 Module 下的每一个布局文件生成一个绑定对象,这个说法在布局文件被另一个布局文件使用 include 引入时依然适用。
△ 视图绑定中使用 include 标签的示例 注意: include 标签下有一个 id。
在使用引入布局的时候,视图绑定会创建一个被引入布局绑定对象的引用。注意 include>标签有一个 id: android:id="@+id/includes"。这里的逻辑跟使用普通视图一样, include 标签也需要有一个 id 才能在绑定对象中生成对应的属性。
include 标签必须有一个 id,才能生成对应的属性。
public final class ActivityAwesomeBinding implements ViewBinding { ... @NonNull public final IncludedButtonsBinding includes;
视图绑定会在 ActivityAwesomeBinding 中生成一个 IncludedButtonsBinding 的引用。
结合数据绑定来使用视图绑定
视图绑定只是 findViewById 的取代方案,如果您希望在 XML 中自动绑定视图,可以使用 数据绑定 库。数据绑定和视图绑定可以生成同样的组件,它们可以同时工作。
在两者都被开启时,使用 标签的布局会由数据绑定来生成绑定对象;而其余的布局则由视图绑定生成绑定对象。
您可以在同一 Module 中同时使用数据绑定和视图绑定。
我们之所以开发视图绑定作为数据绑定的补充,是因为许多开发者反映说,希望有一个轻量的解决方案,能在数据绑定之外替代 findViewById——视图绑定提供的正是这一功能。
视图绑定对比 Kotlin 合成方法与 ButterKnife
关于视图绑定,一个最常见的问题是: "我是否应该用视图绑定替代 Kotlin 合成方法或 ButterKnife ? " 二者都是目前十分成功的组件库,有许多应用使用它们解决 findViewById 的问题。
对于大多数应用来说,我们推荐尝试使用视图绑定来替代这两个库,因为视图绑定可以提供更加安全和准确的视图映射方式。
△ 视图绑定空安全、只引用当前布局中的视图、支持 Java 和 Kotlin,同时也更简洁
上图为对比视图绑定、ButterKnife 和 Kotlin 合成方法的功能。
虽然 ButterKnife 会在运行时校验可空与不可空,但是编译器并不会检查您匹配的视图是否在存在于您的布局之中。
为了安全性与更简洁代码,我们推荐尝试使用视图绑定。
点击这里了解更多有关视图绑定的信息。
将视图转为image_使用视图绑定替代 findViewById相关推荐
- CREO:CREO软件之工程图【插入页面】、【装配图出工程图】、【将视图转为绘制图元】、【工程图输入到CAD中去修改】的简介及其使用方法(图文教程)之详细攻略
CREO:CREO软件之工程图[插入页面].[装配图出工程图].[将视图转为绘制图元].[工程图输入到CAD中去修改]的简介及其使用方法(图文教程)之详细攻略 目录
- CREO:CREO软件之工程图界面的简介(【创建】、【布局】、【表】、【注释】、【插入页面】、【装配图出工程图】、【将视图转为绘制图元】、【工程图输入到CAD中去修改】)图文教程之详细攻略
CREO:CREO软件之工程图界面的简介([创建].[布局].[表].[注释].[插入页面].[装配图出工程图].[将视图转为绘制图元].[工程图输入到CAD中去修改])图文教程之详细攻略 目录 CR ...
- mysql oracle创建视图索引吗_Oracle视图,索引,序列
什么是视图[View] (1)视图是一种虚表 (2)视图建立在已有表的基础上, 视图赖以建立的这些表称为基表 (3)向视图提供数据内容的语句为 SELECT 语句,可以将视图理解为存储起来的 SELE ...
- MySQL 学习笔记(5)— 视图优缺点、创建视图、修改视图、删除视图
1. 视图概念 简单来说,视图就是一个预定义的查询语句.视图在许多情况下可以当作表来使用,因此也被称为虚拟表(Virtual Table). 视图与表最大的区别在于它不包含数据,数据库中只存储视图的定 ...
- SpringMVC核心——视图渲染(包含视图解析)问题
一.本来想说的是返回值处理问题,但在 SpringMVC 中,返回值处理问题的核心就是视图渲染.所以这里标题叫视图渲染问题. 本来想在上一篇文章中对视图解析进行说明的,但是通过源码发现,它应该算到视图 ...
- SQL Server索引视图以(物化视图)及索引视图与查询重写
SQL Server索引视图以(物化视图)及索引视图与查询重写 本文出处:http://www.cnblogs.com/wy123/p/6041122.html 经常听Oracle的同学说起来物化视图 ...
- mysql实现物化视图详解及视图与物化视图区别
再一次sql优化中一个select count(*)语句因数据量实在太大,已经无法从简单的索引什么进行优化了,在同事的推荐下考虑到了物化视图 物化视图是相对于视图而言的,但是两者实际上并没有什么关系就 ...
- oracle查看视图定义语句_oracle视图详解
Oracle 视图详解 一. 视图的定义 视图(view),也称虚表, 不占用物理空间,这个也是相对概念,因为视图本身的定义语句还是要存储在数据字典里的.视图只有逻辑定义.每次使用的时候,只是重新执行 ...
- oracle查询视图时慢,oracle视图查询速度慢
一般对视图的查询最好都分解为对数据表的 直接查询效果要好一些. 可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参 数,这个参数在SGA共享池中保留一个连续的内存空间,连 续的内 ...
最新文章
- Thrift协议与传输选择
- 建设微服务API网关的一些实践
- Cocos2d-x 处理双击事件的两种方法
- Linux忘记密码常用的几种解决方法
- 效率系列(四) VS常用快捷键
- 在索引列上正确使用LIKE运算符
- 典型相关分析_微生物多样研究—微生物深度分析概述
- threejs 绘制球体_Three.js 第一篇:绘制一个静态的3D球体
- Tuple and Tie
- mysql 字段有正负值的时候 sum无效_京东金融数据分析:MySQL+HIVE的结合应用案例详解...
- keepalived 非抢占模式
- 正在考虑微服务架构的松耦合?小心这些陷阱
- 时间序列数据建模分析利器sktime初体验
- ElasticSearch IK配置同义词
- Java web项目中获取WebRoot目录下的文件
- oreo授权系统V1.1开源版
- python运行部分代码
- What The F**k Python!!!
- iClone走路改为原地踏步
- 能力提升的僵化、优化、固化过程
热门文章
- HTML+CSS+JS实现 ❤️乐队成员图片展示ui特效❤️
- java防止编码重复_java – 如何避免许多小类的代码重复?
- 自带容器_什么是衬胶容器罐以及质量标准?
- 异常信息_一个针对异常信息通知的springboot starter
- Session 'app': Installation did not succeed.The application could not be installed: INSTALL FAILED I
- 没有bug队——加贝——Python 练习实例 17,18
- SQL Server常用约束表达式实例
- Jupyter 快速入门
- 易语言mysql乱码_分享一个解决MySQL写入中文乱码的方法
- all any 或 此运算符后面必须跟_any和all组合运算符用法区别