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

Android DataBinding 基础入门(学习记录)

目录

      • 一、DataBinding简介
      • 二、findViewById 和 DataBinding 原理及优缺点
        • 1. findViewById的优缺点
        • 2. DataBinding的优缺点
      • 三、Android mvvm 之 databinding 原理
        • 1. 简介和三个主要的实体
          • Data
          • View
          • ViewDataBinding
        • 2.三个功能
          • 2.1. rebind 行为
          • 2.2 observe data 行为
          • 2.3 observe view 行为
      • 四、代码实例

一、DataBinding简介

DataBinding 是谷歌官方发布的一个框架,顾名思义即为数据绑定,是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。MVVM 相对于 MVP,其实就是将 Presenter 层替换成了 ViewModel 层。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常

二、findViewById 和 DataBinding 原理及优缺点

1. findViewById的优缺点

findViewById的原理:Android中的View结构是一个树形结构,findViewById就是自树的根节点,依次遍历其子节点,知道找到目标的id。

  • findViewById的优点
    • 兼容性好,下面各种替代方案,都有其适用的场景,但是findViewById适用所有的场景,当你不知道用哪种方案的时候,那就用findViewById吧,肯定没有错。
    • 非常灵活,适合动态加载layout文件。比如一个Activity,需要在不同的业务中,加载两个不同的layout文件,但是两个layout文件只有部分间距不同,其他各个元素都是相同的。这个时候,用findViewId就可以完美适用。
  • findViewById的缺点
    • 性能略差不好,findViewById是基于树形结构的查找,理论上会带来性能的额外开销,但是实际项目中,因为控件的个数也不会非常非常多,所以可以忽略不计。;
    • Fragment中使用容易犯错。从原理图可以看到,在Activity中调用findViewById,实际上是调用Window中的findViewById,但是Fragment中并没有单独的Window,Fragment中调用findViewById的效果和Activity中调用的效果一模一样。所以如果一个Activity中有多个Fragment,Fragment中的控件名称又有重复的,那直接findViewById会出错的;
    • 增加代码的耦合度,findViewById随时实地都可以调用,在子view中,在Activity中等等,如果滥用起来,会让代码耦合的一塌糊涂,后面查找bug起来,非常麻烦,因为不知道View的属性在哪个类中被改变了;
    • 容易引发空指针,一个大型项目中,控件的id经常会重复,xml中删除了一个控件,但是对应的Activity中没有删除这个控件的相关引用,编译时并不会报错,但是运营室时会报出空指针;
    • 代码可读性不好,findViewById往往在Activity的onCreate方法中被引用,我们不能方便的将xml中的控件与代码中的控件结合起来,特别是如果xml的命名与代码中的命名又不规范,代码阅读起来简直就是噩梦。

2. DataBinding的优缺点

databinding会根据动态生成一个ActivityMainBinding文件,在执行ActivityMainBinding.inflate的时候,会自动生成控件的引用(mapBindings方法),这里对布局tree执行一趟遍历查找就可以生成所有的引用

  • DataBinding的优点

    • 规避了控件空指针错误,如果有引用错误,则会在编译阶段发现;
    • 效率比findViewById要高,一趟遍历可以生成所有控件的引用,而findViewById是每次执行时都需要遍历一遍
    • 代码的可读性要高,得益于Android Studio的强大功能,我们很轻易的将java(kotlin)代码中的控件引用与xml的定义结合起来
  • DataBinding的缺点

    • 灵活性不高,如果需要动态选取引用的布局文件,binding就无法适用了。
    • 改造成本较大,布局文件只有加上layout标签才可以使用。

原文链接

参考博客

三、Android mvvm 之 databinding 原理

原文

1. 简介和三个主要的实体

Data Binding 的结构[Top]
作为在 Android 开发中体现 MVVM 架构思想的 Data Binding,其核心是 观察者模式 的特定实现。首先,它有三个主要的实体:

Data

与 View 相关的数据,它可以是 View 的可观察者对象;

View

展示给用户的视图,如果有交互功能且能更新数据,它可以是 Data 的可观察者对象;

ViewDataBinding

连接 Data 和 View 的中介,当 Data 或 View 作为可观察者对象时,它充当可观察者对象的代理。假如当我们写了一个名为 demo.xml 的 Data Binding 的 layout 文件后,编译工具会生成一个相应的类——DemoBinding,它的原型就是 ViewDataBinding。我们通常通过 DataBindingUtil.inflate(inflater, R.layout.demo, container, false) 来实例化的 DemoBinding 对象,即 ViewDataBinding。

2.三个功能

其次,它主要提供了以下三个方面的功能:
将特定的 View 与特定的 Data 进行绑定,便于模块化;
View 自动感知和响应 Data 的变化,使得处理数据的业务层不必关心 View 的状态,便于解耦;
Data 也可以自动同步带有交互功能的 View 对数据的修改,使得 UI 层的交互不必担心数据是否能同步 View 状态的问题,仍然便于解耦。
基于这三个功能,Data Binding 的结构也可以划分为三个行为模式,以下一一介绍:

2.1. rebind 行为

首先,Data 往往是一个数据的集合,数据绑定的第一步就是要将整个 Data 集合绑定到 View,比如初始化和数据的整体更新,如下图所示:
在这里插入图片描述
可以观察到,rebind 的过程就是一个简单的赋值操作,将 View 的值设置为 Data,只不过由 ViewDataBinding 这个代理来完成这个工作。图中的 _all 参数表示将 View 的所有需要更新的节点都设置为 Data 的所有对应的成员值。当我们在 layout 文件中进行如下设置时,ViewDataBinding 将代理完成 View 中所有数据绑定节点的 data rebind 操作:

2.2 observe data 行为

有时候,我们并不需要每次更新整个 Data 集合,而只需要更新集合中的某一个成员。我们希望看到的结果是,当 Data.element_i 发生变化的时候,View.child_i 更新就可以了,而不需要将 View 的所有视图节点都重新渲染一遍。要做到这一点,我们必须要让 View 可以观察 Data 的行为。换句话说,Data 是一个可观察者对象——这是 Data Binding 中另一个魅力所在,其行为模式如下:
在这里插入图片描述
我们可以将任何数据作为一个 Observable,然后将 ViewDataBinding 作为 View 的代理观察者,订阅 Data 的成员变化,一旦 Data 成员变化,便通知所有观察者对象——即 ViewDataBinding,然后 ViewDataBinding 再将 View 的相应节点的值设置为 Data 相应成员的新值——即图中的 _member 参数。

这里有三个关键部分:
BaseObservable:可观察者基类(实际的祖先基类是一个 Observable 接口),实现改接口后,ViewDataBinding 就会在每次 rebind 的时候去订阅 Data 的变化;
@Bindable 标注:声明该成员是可被观察的,以及在 layout 中可以以 http://Data.xxx(标注的方法名如果为 getXXX)的方式进行访问;
notifyPropertyChanged 方法:BaseObservable 用于通知具体成员发送变化的方法,只要该方法被调用,ViewDataBinding 就会检索出是哪一个 element 的变化,并只对 View 相应的节点进行更新。

2.3 observe view 行为

在开发中,根据业务需求,我们一般能遇到两种类型的 View:
一种是只用于展示的 View,它只展示 UI 状态,而不反馈状态,我们称之为 单工View;
另一种除了展示以外,还会反馈状态给监听者,我们称之为 双工View。
在 Android 的 UI事件流中,因为所有的 View 都是可以反馈状态的,所以准确来说,所有的 View 其实都是双工的。我们在这里区分单工和双工是针对业务需求的,比如:我们很多的视图只需要它们展示就可以了,不需要监听它们的状态变化,那么我们将其归为单工View。

费尽心思进行这样的划分,是因为,单工View 只需要有 observe data 行为就可以了;而双工View 往往就需要 observe view 行为。具体来说,在反馈状态时需要更新 Data 的双工 View,我们需要进行 observe view 行为。

因为双工View 会更新 Data,所以为了保证数据的一致性,Data 需要观察双工View 的状态变化。要做到这一点,这样的双工View 必须是一个可观察者对象。得益于 UI事件流的实现,双工View天然是可观察的(只要能反馈状态,就意味着能被观察)。在自定义的双工View中,可以间接引用 ViewDataBinding,这样 ViewDataBinding 就可以代理 Data 订阅 View 的状态变化:
在这里插入图片描述

四、代码实例

启用 DataBinding 的方法是在对应 Model :appbuild.gradle 文件里加入以下代码,同步后就能引入对 DataBinding 的支持

android {dataBinding {enabled = true}
}

1、在布局文件中绑定指定的变量打开布局文件,选中布局文件的第一行,按住 Alt + 回车键,点击 “Convert to data binding layout”,就可以生成 DataBinding 需要的布局规则
在这里插入图片描述
在这里插入图片描述
和原始布局的区别在于多出了一个 layout 标签将原布局包裹了起来,data 标签用于声明要用到的变量以及变量类型,要实现 MVVM 的 ViewModel 就需要把数据(Person)与 UI(View)进行绑定,data 标签的作用就像一个桥梁搭建了 View 和 Person 之间的通道

Person类

public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

在 data 标签里声明要使用到的变量名、类的全路径(如果 Person类型要多处用到,也可以直接将之 import 进来,就不用每次都指明整个包名路径)

<data><variablename="per1"type="com.example.databindingpro.Person" /><variablename="work"type="String" /></data>

如果存在 import 的类名相同的情况,可以使用 alias 指定别名

    <data><import type="com.leavesc.databinding_demo.model.User" /><importalias="TempUser"type="com.leavesc.databinding_demo.model2.User" /><variablename="userInfo"type="User" /><variablename="tempUserInfo"type="TempUser" /></data>

这里声明了一个 Person类型的变量per1,我们要做的就是使这个变量与两个 TextView 控件挂钩,通过设置per1的变量值同时使 TextView 显示相应的文本 完整的布局代码如下所示

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"><data><variablename="per1"type="com.example.databindingpro.Person" /><variablename="work"type="String" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{per1.name}"android:textSize="30dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(per1.age)}"android:textSize="30dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{work}"android:textSize="30dp"/></LinearLayout></LinearLayout>
</layout>

通过 @{per1.name}使 TextView 引用到相关的变量,DataBinding 会将之映射到相应的 getter 方法 之后可以在 Activity 中通过 DataBindingUtil 设置布局文件,省略原先 Activity 的 setContentView() 方法,并为变量per1 赋值

import androidx.databinding.DataBindingUtil;
import android.app.Activity;
import android.os.Bundle;
import com.example.databindingpro.databinding.ActivityMainBinding;
public class MainActivity extends Activity {private ActivityMainBinding mActivityMainBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//setContentView(R.layout.activity_main);mActivityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);com.example.databindingpro.Person person = new com.example.databindingpro.Person("张三",23);mActivityMainBinding.setPer1(person);//给布局文件name="per1"传入数据,类型为Person对象mActivityMainBinding.setWork("Teacher");//给布局文件name="work"传入数据,类型为String字符串}
}

效果:
在这里插入图片描述

相关文章:

Android DataBinding 基础入门(学习记录)

目录 一、DataBinding简介二、findViewById 和 DataBinding 原理及优缺点1. findViewById的优缺点2. DataBinding的优缺点 三、Android mvvm 之 databinding 原理1. 简介和三个主要的实体DataViewViewDataBinding 2.三个功能2.1. rebind 行为2.2 observe data 行为2.3 observe …...

spring 错误百科

一、使用Spring出错根源 1、隐式规则的存在 你可能忽略了 Sping Boot 中 SpringBootApplication 是有一个默认的扫描包范围的。这就是一个隐私规则。如果你原本不知道&#xff0c;那么犯错概率还是很高的。类似的案例这里不再赘述。 2、默认配置不合理 3、追求奇技淫巧 4、…...

OpenCV基本操(IO操作,读取、显示、保存)

图像的IO操作&#xff0c;读取和保存方法 1.1 API cv.imread()参数&#xff1a; 要读取的图像 读取图像的方式&#xff1a; cv.IMREAD*COLOR:以彩色模式加载图像&#xff0c;任何图像的图像的透明度都将被忽略。这是默认参数 标志&#xff1a; 1 cv.IMREAD*GRAYSCALE :以…...

1.快速搭建Flask项目

一.Pear Admin Flask 官网文档:http://www.pearadmin.com/doc/index.html 1.1下载安装 # 下 载 git clone https://gitee.com/pear-admin/pear-admin-flask# 安 装 pip install -r requirements.txt1.2修改配置 applications下的config.py docker运行的修改dockerdata/conf…...

编程题四大算法思想(三)——贪心法:找零问题、背包问题、任务调度问题、活动选择问题、Prim算法

文章目录 贪心法找零问题&#xff08;change-making problem&#xff09;贪心算法要求基本思想适合求解问题的特征 背包问题0/1背包问题0/1背包问题——贪心法 分数背包问题 任务调度问题活动选择问题活动选择——贪心法最早结束时间优先——最优性证明 Prim算法 贪心法 我在当…...

core dump管理在linux中的前世今生

目录 一、什么是core dump&#xff1f; 二、coredump是怎么来的&#xff1f; 三、怎么限制coredump文件的产生&#xff1f; ulimit 半永久限制 永久限制 四、从源码分析如何对coredump文件的名字和路径管理 命名 管理 一些问题的答案 1、为什么新的ubuntu不能产生c…...

Springboot整合knife4j配置swagger教程-干货

开启swagger文档&#xff0c;直接上教程。 第一步:引入依赖 <!--swagger 依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></d…...

C++ 中的 Pimpl 惯用法

C 中的 Pimpl 惯用法 介绍 Pimpl&#xff08;Pointer to Implementation&#xff09;是一种常见的 C 设计模式&#xff0c;用于隐藏类的实现细节&#xff0c;从而减少编译依赖和提高编译速度。本文将通过一个较为复杂的例子&#xff0c;展示如何使用智能指针&#xff08;如 s…...

【个人博客系统网站】统一处理 · 拦截器

【JavaEE】进阶 个人博客系统&#xff08;2&#xff09; 文章目录 【JavaEE】进阶 个人博客系统&#xff08;2&#xff09;1. 统一返回格式处理1.1 统一返回类common.CommonResult1.2 统一返回处理器component.ResponseAdvice 2. 统一异常处理3. 拦截器实现3.1 全局变量SESSI…...

深入探索PHP编程:文件操作与输入/输出(I/O)

深入探索PHP编程&#xff1a;文件操作与输入/输出&#xff08;I/O&#xff09; 在PHP编程中&#xff0c;文件操作和输入/输出&#xff08;I/O&#xff09;是不可或缺的关键部分。无论是读取、写入文件&#xff0c;还是处理上传的文件&#xff0c;这些操作都是Web开发的重要组成…...

基于jeecg-boot的flowable流程自定义业务驳回到发起人的一种处理方式

有些粉丝&#xff0c;希望对自定义业务中&#xff0c;驳回到发起人进行处理&#xff0c;比如可以重新进行发起流程&#xff0c;下面就给出一种方式&#xff0c;当然不一定是最好的方式&#xff0c;只是提供一种参考而已&#xff0c;以后可以考虑动态根据流程状态或节点信息进行…...

【大数据知识】大数据平台和数据中台的定义、区别以及联系

数据行业有太多数据名词&#xff0c;例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆&#xff0c;也很容易产生疑问&#xff0c;今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台&#xff1a;一个…...

华为OD:IPv4地址转换成整数

题目描述&#xff1a; 存在一种虚拟IPv4地址&#xff0c;由4小节组成&#xff0c;每节的范围为0-255&#xff0c;以#号间隔&#xff0c;虚拟IPv4地址可以转换为一个32位的整数&#xff0c;例如&#xff1a; 128#0#255#255&#xff0c;转换为32位整数的结果为2147549183&#…...

2023.9 - java - 浅拷贝

与 js的浅拷贝不同&#xff1a; 在 JavaScript 中&#xff0c; Object.assign() 或 spread 运算符等方法可以实现浅拷贝&#xff0c;但只针对对象的第一层属性进行复制。如果一个对象只包含基本数据类型的属性&#xff0c;那么对浅拷贝出来的对象进行修改不会影响原始对象&…...

STM32f103入门(10)ADC模数转换器

ADC模数转换器 ADC简介AD单通道初始化代码编写第一步开启时钟第二步 RCCCLK分频 6分频 72M/612M第三步 配置GPIO 配置为AIN状态第四步&#xff0c;选择规则组的输入通道第五步 用结构体 初始化ADC第六步 对ADC进行校准编写获取电压函数初始化代码如下 Main函数编写 ADC简介 ADC…...

实训笔记8.28

实训笔记8.28 8.28笔记一、大数据计算场景主要分为两种1.1 离线计算场景1.2 实时计算场景 二、一般情况下大数据项目的开发流程2.1 数据采集存储阶段2.2 数据清洗预处理阶段2.3 数据统计分析阶段2.4 数据挖掘预测阶段2.5 数据迁移阶段2.6 数据可视化阶段 三、纯大数据离线计算项…...

机器学习笔记之最优化理论与方法(五)凸优化问题(上)

机器学习笔记之最优化理论与方法——凸优化问题[上] 引言凸优化问题的基本定义凸优化定义&#xff1a;示例 凸优化与非凸优化问题的区分局部最优解即全局最优解凸优化问题的最优性条件几种特殊凸问题的最优性条件无约束凸优化等式约束凸优化非负约束凸优化 引言 本节将介绍凸优…...

在Windows10上编译grpc工程,得到protoc.exe和grpc_cpp_plugin.exe

grpc是google于2015年发布的一款跨进程、跨语言、开源的RPC(远程过程调用)技术。使用C/S模式&#xff0c;在客户端、服务端共享一个protobuf二进制数据。在点对点通信、微服务、跨语言通信等领域应用很广&#xff0c;下面介绍grpc在windows10上编译&#xff0c;这里以编译grpc …...

一些测试知识

希望能起到帮助&#xff0c;博主主页&#xff1a; https://blog.csdn.net/qq_57785602/category_12023254.html?spm1001.2014.3001.5482 软件测试理论 测试的依据&#xff1a; 需求&#xff0c;规格说明&#xff0c;模型&#xff0c;用户需求等 什么是软件测试 描述一种来…...

Socket交互的基本流程?

TCP socket通信过程图 什么是网络编程&#xff0c;网络编程就是编写程序使两台连联网的计算机相互交换数据。怎么交换数据呢&#xff1f;操作系统提供了“套接字”&#xff08;socket&#xff09;的组件我们基于这个组件进行网络通信开发。tcp套接字工作流程都以“打电话”来生…...

css 分割线中间带文字

效果图 代码块&#xff08;自适应&#xff09; <div class"line"><span class"text">我是文字</span></div>.line{height:0;border-top:1px solid #000;text-align:center;}.text{position:relative;top:-14px;background-color:#…...

会不会激发对modern c++的新兴趣

可变参数好像很厉害的样子&#xff0c;会节省很多手写代码&#xff0c;让编译器自动帮我们生成代码 template<typename Fun, typename...Args> void invoke(Fun&& fun, Args&&...args) { fun(std::forward<Args>(args)...); } 任意函数包装器…...

Nginx服务器如何配合Java开发项目

Nginx服务器如何才能配合好相关的编程语言进行服务器搭建呢&#xff1f;下面我们就来看看有关的技术如何融合。希望大家有所收获。 在进行Nginx服务器建设的时候有很多语言的应用&#xff0c;其中Java 开发的web项目就是很常见的。下面我们就看看Nginx服务器如何才能与Java编程…...

【LeetCode-中等题】994. 腐烂的橘子

文章目录 题目方法一&#xff1a;bfs层序遍历 题目 该题值推荐用bfs&#xff0c;因为是一层一层的感染&#xff0c;而不是一条线走到底的那种&#xff0c;所以深度优先搜索不适合 方法一&#xff1a;bfs层序遍历 广度优先搜索&#xff0c;就是从起点出发&#xff0c;每次都尝…...

K8s部署单机mysql

文章目录 一、K8s部署单机mysql1.1 说明1.2 不足 二、部署三、检查 一、K8s部署单机mysql 1.1 说明 定制配置数据存放在configMapmysql数据放在/opt/mysql目录下(/opt/mysql目录需要事先创建)root账号密码使用环境变量env服务暴露方式为nodePort&#xff0c;端口30336 1.2 不…...

Midjourney学习(二)参数的基础

prompt的组成 prompt 可以由三部分组成&#xff0c; 第一部分是垫图部分&#xff0c;也就是一张网络图片 第二部分是文本描述内容 第三部分则是参数 参数列表 --aspect <value> 或者 --ar <value> 控制画面的比例&#xff0c;横竖比例 --version <value> -…...

Ubuntu安装Protobuf,指定版本

参考&#xff1a;https://github.com/protocolbuffers/protobuf#readme https://github.com/protocolbuffers/protobuf/blob/v3.20.3/src/README.md 其实官网的readme给的步骤很详细。 1.安装相关依赖 sudo apt-get install autoconf automake libtool curl make g unzip …...

没有使用sniffer dongle在windows抓包蓝牙方法分享

网上很多文章都是介绍买一个sniffer dongle来抓蓝牙数据,嫌麻烦又费钱,目前找到一个好方法,不需要sniffer就可以抓蓝牙数据过程,现分享如下: (1)在我资源附件找到相关安装包或者查看如下链接 https://learn.microsoft.com/zh-cn/windows-hardware/drivers/bluetooth/testing-bt…...

解决Debian系统通过cifs挂载smb后,中文目录乱码问题

解决Debian系统通过cifs挂载smb后&#xff0c;中文目录乱码问题 //$smb_server/share /mnt/nas_share cifs credentials/root/.smbcredentials,iocharsetutf8 0 0默认通过以上命令挂载smb&#xff0c;但是在查看文件目录时&#xff0c;中文乱码 解决问题方式&#xff1a; de…...

springboot整合jquery实现前后端数据交互

一 实施逻辑 1.1 前端 <!doctype html> <html lang"en"><head><meta charset"UTF-8"><meta name"Generator" content"EditPlus"><meta name"Author" content""><meta n…...