移动架构47_视图绑定组件ViewBinding

news/2024/10/17 20:18:12/

Android移动架构汇总​​​​​​​

文章目录

    • 一、控件的声明
    • 二、ViewBinding的基本使用
    • 三、ViewBinding特点
    • 四、ViewBinding的封装
    • 五、源码

一、控件的声明

在Activity中绑定布局中的控件一般有三种实现方式:

  • 第一种用最原生态的findViewById方法来绑定
  • 第二种方式可以使用ButterKnife开源框架实现,ButterKnife对组件化的支持却很不友好
  • 第三种方式是使用Kotlin的扩展插件来获取视图控件,使用局限性:无法跨模块操作,类型不安全:不同的资源文件可以存在相同的控件id,因此在View层存在引用id来源出错的问题。

Kotlin 1.4版本中废弃了扩展插件,Google推荐使用ViewBinding来替代废弃的扩展插件

二、ViewBinding的基本使用

build.gradle中添加如下配置:

android {...viewBinding {enabled = true}...
}

配置完成后,系统会为该模块中的每个XML布局文件生成一个绑定类,这个绑定类的命名就是XML文件的名称转换为驼峰式,并在末尾添加“Binding”一词,直接可以通过view binding这一中间类获取到xml中定义的view组件了

@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// setContentView(R.layout.activity_new_stock_bjs_records);viewBinding = ActivityNewStockBjsRecordsBinding.inflate(getLayoutInflater());viewBinding.navigationBar.setText("北交所新股申购")}

需要注意的一点是,开发者需要在onDestroyView()方法中将绑定类实例赋值为null。Fragment的存在时间比其视图时间长,所以开发者需要在onDestroyView()方法中清除对绑定类实例的所有引用,否则可能存在内存泄漏的风险

注意
如果某个布局文件不需要的话,可以通过tools:viewBinding-Ignore=“true”属性来设置

三、ViewBinding特点

  1. 集成简单
  2. 代码简洁,维护容易
  3. 对象空值安全:由于视图绑定会对视图直接引用,因此不存在因视图id无效而引发空指针异常的风险。
  4. 类型安全:每个绑定类中的字段均具有与它们在xml文件中引用的视图相匹配的类型,因此不存在强制转换可能导致的异常问题

四、ViewBinding的封装

ViewBinding组件的使用流程基本是固定的,主要分为三步:

  1. 调用生成的绑定类中的inflate()方法来获取绑定类的实例。
  2. 通过调用绑定类的getRoot()方法获取对根视图。
  3. 将根视图传递到setContentView()中,并与当前Activity绑定。
    由于ViewBinding使用的流程是固定的,因此在基础业务的开发中,经常会定义一个BaseActivity处理所有Activity的相同业务逻辑,这时,就可以将这部分逻辑封装在BaseActivity中
/*** 使用ViewBinding的基础类** @param <T>*/
public abstract class ViewBindingBaseActivity<T extends ViewBinding> extends ActivityBase {protected T mViewBinding;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);mViewBinding = getViewBinding();setContentView(mViewBinding.getRoot());}/*** @return 返回Activity对于xml生成的ViewBinding对象*/public abstract T getViewBinding();}

五、源码

在项目模块的build.gradle中开启ViewBinding功能之后,若进行项目编译,就会扫描layout下所有的布局文件,并生成对应的绑定类(Project视图:
app/build/generated/data_binding_base_class_source_out/debug/out/包名/databinding路径下)。这一点是由gradle插件实现的

public final class ActivityTestBinding implements ViewBinding {@NonNullprivate final LinearLayout rootView;@NonNullpublic final ImageView imShezhi;@NonNullpublic final HomeRefresh reRefresh;@NonNullpublic final RecyclerView rv;@NonNullpublic final TextView tvName;private ActivityTestBinding(@NonNull LinearLayout rootView, @NonNull ImageView imShezhi,@NonNull HomeRefresh reRefresh, @NonNull RecyclerView rv, @NonNull TextView tvName) {this.rootView = rootView;this.imShezhi = imShezhi;this.reRefresh = reRefresh;this.rv = rv;this.tvName = tvName;}@Override@NonNullpublic LinearLayout getRoot() {return rootView;}@NonNullpublic static ActivityTestBinding inflate(@NonNull LayoutInflater inflater) {return inflate(inflater, null, false);}@NonNullpublic static ActivityTestBinding inflate(@NonNull LayoutInflater inflater,@Nullable ViewGroup parent, boolean attachToParent) {View root = inflater.inflate(R.layout.activity_test, parent, false);if (attachToParent) {parent.addView(root);}return bind(root);}@NonNullpublic static ActivityTestBinding bind(@NonNull View rootView) {// The body of this method is generated in a way you would not otherwise write.// This is done to optimize the compiled bytecode for size and performance.String missingId;missingId: {ImageView imShezhi = rootView.findViewById(R.id.im_shezhi);if (imShezhi == null) {missingId = "imShezhi";break missingId;}HomeRefresh reRefresh = rootView.findViewById(R.id.re_refresh);if (reRefresh == null) {missingId = "reRefresh";break missingId;}RecyclerView rv = rootView.findViewById(R.id.rv);if (rv == null) {missingId = "rv";break missingId;}TextView tvName = rootView.findViewById(R.id.tv_name);if (tvName == null) {missingId = "tvName";break missingId;}return new ActivityTestBinding((LinearLayout) rootView, imShezhi, reRefresh, rv, tvName);}throw new NullPointerException("Missing required view with ID: ".concat(missingId));}
}

从生成的ActivityTestBinding文件中可以轻松地看出,在调用了inflate之后会调用bind方法,而bind方法依然是通过findViewById绑定


http://www.ppmy.cn/news/55585.html

相关文章

辨析 确认范围、核实产品、质量控制、项目收尾

确认范围、核实产品、质量控制、项目收尾 辨析 确认范围与核实产品 确认范围针对项目可交付成果&#xff0c;由客户或发起人在阶段末确认验收的过程 核实产品针对产品是否完成&#xff0c;由客户或发起人在阶段末确认产品是否完整 确认范围与质量控制 不同点 强调内容不同…

不得不说的结构型模式-代理模式

目录 代理模式&#xff1a; 下面是一个简单的C代码案例 下面是面试中可能遇到的问题&#xff1a; 代理模式&#xff1a; 代理模式是一种结构型设计模式&#xff0c;它通过引入一个代理对象来控制对另一个对象的访问。代理对象充当原始对象的中介&#xff0c;通过拦截对原始…

模型服务,支持渲染多张输出图片|ModelWhale 版本更新

清明时节雨纷纷。晚春的雨季中&#xff0c;ModelWhale 迎来了新一轮的版本更新。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; • 新增 模型服务多图输出渲染&#xff08;专业版✓ 团队版✓ &#xff09; • 优化 门户成果交流展示&#xff08;团队…

Python使用CV2库捕获、播放和保存摄像头视频

Python使用CV2库捕获、播放和保存摄像头视频 特别提示&#xff1a;CV2指的是OpenCV2&#xff08;Open Source Computer Vision Library&#xff09;&#xff0c;安装的时候是 opencv_python&#xff0c;但在导入的时候采用 import cv2。 若想使用cv2库必须先安装&#xff0c;P…

【C++】 小项目---宠物小屋的分析设计与开发实现

目录 需求 分析设计 动物类 笼子类 房子类 人类 小贴士 整体设计图 开发实现 动物类 笼子类 房子类 人类 小贴士 控制台主函数 需求 动物猫&#xff08;CCat&#xff09;、狗&#xff08;CDog&#xff09;、蛇&#xff08;CSnake&#xff09;&#xff0c;包含名字&…

【福利赠书】有人说,测试驱动开发已死?(文末赠书3本)

友情推荐一本测试领域的教科书&#xff1a;&#xff08;文末送3本&#xff09; 《 测试驱动开发&#xff1a;入门、实战与进阶》&#xff0c;英文原书名为《Learning Test-Driven Development 》&#xff0c;是一本实用且有趣的TDD实践教程。如果你想开始做测试驱动开发&#x…

基于全过程通道相关像素值顺序的彩色图像可逆数据隐藏

文献学习&#xff1a; 基于全过程通道相关像素值顺序的彩色图像可逆数据隐藏 原文题目&#xff1a; Reversible data hiding for color images based on pixel value order of overall process channel. 发表期刊&#xff1a; Signal Processing&#xff08;中科院二区&#xf…

设计模式之建造者模式

1、什么是建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于…