DataBinding简易入门

简介

DataBinding是Google在18年推出的数据绑定框架,采用了MVVM模式来降低各模块之间代码的耦合度,使得整体代码逻辑设计更加清晰。众所周知,MVVM类似于MVC,主要目的是为分离View(视图)和Model(模型),同时进行双向数据绑定,当业务数据发生改变时,View能及时刷新;当View数据更新时,同时能同步到Model。同时,DataBinding能省去findViewById()操作,大量减少Activity内代码,根据业务场景,可以让数据能单向或双向绑定到对应界面layout中,能较好的避免空指针,以及防范内存泄漏。

使用

启用方式,在Module的build.gradle中构建:

android {    ...   buildFeatures {dataBinding true    }
}

1、布局绑定

在要编写的布局文件中选定根布局,按Alt+回车快捷键唤出提示:

image.png
选择第一个即可生成符合DataBinding规则的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity">...</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

可看见原根布局被包裹住了,且布局元素上方出现< data>标签,在这< data>标签是用于声明要用到的变量以及变量类型,在MVVM模式中扮演的是一个View和Model通讯的中间人角色。

生成dataBinding规则的布局后,数据绑定库会自定生成将布局中的视图和数据绑定所需的类,类名为layout.xml文件名+DataBinding的驼峰规则命名组合(这点与ViewBinding类似)。

比如:我这个是MainActivity.class,布局文件为activity_main.xml,则相应绑定类类名为 ActivityMainBinding 。

2、绑定流程

步骤一:先编写一个简单的实体Bean类:

java版:

public class UserInfo {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;}private String name;private int age;}

kt版:

data class UserInfo(val name: String,val age: Int) {}

步骤二:在布局文件中的里引用要使用到的变量名、类的全路径,如下:

<data><variablename="UserInfoExample"type="com.example.dbjavatest.bean.UserInfo" /></data>

在这里,中的name可以随意命名,但建议跟实体bean类一致,以免后续遗忘;type则为对应实体bean类的全路径

PS 这里有两个极少数情况:后续你可能发现如果要多出引用这个bean实体类,要写不同的命名区分,就会变成这样:

<data><variablename="UserInfoExample"type="com.example.dbjavatest.bean.UserInfo" /><variablename="UserInfoExample2"type="com.example.dbjavatest.bean.UserInfo" />...
</data>

这时候可以通过 import 标签声明所有用到的这个实体bean类,以上代码即变为:

<data><import type="com.example.dbjavatest.bean.UserInfo"/><variablename="UserInfoExample"type="UserInfo" /><variablename="UserInfoExample2"type="UserInfo" />...
</data>

如果import标签下两个类名相同,哪怕全路径不同,这里就要使用 alias 来指定别名,如下:

<data><import type="com.example.dbjavatest.bean.UserInfo"/><importalias="NewUserInfo"type="com.example.dbjavatest.otherbean.UserInfo"/><variablename="UserInfoExample"type="UserInfo" /><variablename="UserInfoExample2"type="NewUserInfo" />...
</data>

步骤三:在View中引入数据,使用 @{} 语法,类名即为我们在中定义的name:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><variablename="UserInfoExample"type="com.example.dbjavatest.bean.UserInfo" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_user_first"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{UserInfoExample.name}"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"/><TextViewandroid:id="@+id/tv_user_second"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{UserInfoExample.age}"app:layout_constraintTop_toBottomOf="@+id/tv_user_first"app:layout_constraintStart_toStartOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

可以看出,布局文件里,第一个TextView的text通过@{UserInfoExample.name}引用UserInfo的name属性,第二个TextView的text通过@{UserInfoExample.age}引用UserInfo的age属性。

步骤四:在Activity中实现数据绑定:

java版:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);UserInfo userInfo = new UserInfo("亚历山大", 99);viewDataBinding.setUserInfoExample(userInfo);}
}

kt版:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val viewDataBinding: ActivityMainBinding =DataBindingUtil.setContentView(this, R.layout.activity_main)viewDataBinding.userInfoExample = UserInfo("亚历山大", 99)}
}

可以看到这里不再需要传统的setContentView()指定布局了。直接通过 DataBindingUtil 设置布局文件并得到对应dataBinding对象,并给相应属性赋值,你可以发现此属性的setxxx()并不是bean实体类名,而是布局中里的name属性名。

一运行,发现,报错:

image.png
顺着提示,找下原因,在对应生成的ActivityMainBindingImpl.java类中的116行,如下:

image.png
原因就在此,原UserInfo的实例getAge()返回的是int类型,这里setText里只接受String,按此推断,修改原布局文件就可以了。

<TextViewandroid:id="@+id/tv_user_second"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(UserInfoExample.age)}"app:layout_constraintTop_toBottomOf="@+id/tv_user_first"app:layout_constraintStart_toStartOf="parent"/>

按上述代码修改对应android:text=“”中的属性,运行后可正常发布:

image.png
细心的你可能会发现,xml预览界面中由于没有填写相应数值,致使显示是一片空白。这样不利于我们去观察所设置的TextView颜色大小等属性实际表现结果,这时我们可以去设置默认值来让其在预览界面中显示,格式如下:

android:text="@{UserInfoExample.name,default=defaultValue}"

我们修改原布局中元素属性为:

<TextViewandroid:id="@+id/tv_user_first"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{UserInfoExample.name,default=defaultValue}"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"/><TextViewandroid:id="@+id/tv_user_second"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{UserInfoExample.age,default=25}"app:layout_constraintTop_toBottomOf="@+id/tv_user_first"app:layout_constraintStart_toStartOf="parent"/>

对应生成的预览界面为:

image.png

3、Activity中使用

跟ViewBinding一样,可通过ActivityMainBinding(你对应的activity的dataBinding类)来获取指定id控件,例如:

java版:

viewDataBinding.tvUserFirst.setText("get到了第一个TextView");

kt版:

viewDataBinding.tvUserFirst.text = "get到了第一个TextView"

原布局中,可在< data>标签里指定对应的ViewBinding名称,如果不指定就是默认根据文件名和驼峰原则生成的类名(上面说的activity_main.xml和ActivityMainBinding)。例如:

<data class="DemoBinding">...
</data>

指定中的class后,原activity就已经开始报错了,此时要修改对应的ViewBinding为 DemoBinding 。原来activity中代码则改为了:

java版:

    ...DemoBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);UserInfo userInfo = new UserInfo("亚历山大", 99);viewDataBinding.setUserInfoExample(userInfo);...

kt版:

    ...val viewDataBinding: DemoBinding =DataBindingUtil.setContentView(this, R.layout.activity_main)viewDataBinding.userInfoExample = UserInfo("亚历山大", 99)...

4、在Fragment和RecyclerView中使用

在Fragment中的使用于Activity类似,这里为了方便,Fragment的布局fragment_main.xml内容就跟原activity_main.xml内容保持一致。其activity_main.xml引用此Fragment的布局就修改为(Fragment中id不能省略):

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><variablename="UserInfoExample"type="com.example.dbjavatest.bean.UserInfo" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><fragmentandroid:id="@+id/fragment_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:name="com.example.dbjavatest.MainFragment"/></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Fragment中代码表现则为:

java:

public class MainFragment extends Fragment {@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {FragmentMainBinding viewDataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false);viewDataBinding.setUserInfoExample("屋大维",99);return viewDataBinding.getRoot();}
}

kt:

class MainFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {val viewDataBinding: FragmentMainBinding =DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)viewDataBinding.userInfoExample = UserInfo("屋大维",99)return viewDataBinding.getRoot()}...
}

可见,在Fragment中使用的是 DataBindingUtil对应的inflate(),在onCreateView()中返回对应ViewBinding.getRoot()。其他使用与在Activity中使用一致,这里就不赘述。

同样使用DataBindingUtil.inflate()来获取ViewBinding对象的是RecyclerView的Adapter中:

java版:

...
@NonNull
@Override
public ViewBindHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {ViewDataBinding inflate = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_recyclerview,parent,false);ViewBindHolder viewHolder = new ViewBindHolder(inflate);viewHolder.setmViewBing(viewHolder);return new ViewHolder(inflater);
}
@Override
public void onBindViewHolder(@NonNull ViewBindHolder holder, int position) {holder.bind(...);//传入的UserInfo
}
static class ViewBindHolder extends RecyclerView.ViewHolder{private ItemRecyclerviewBinding mViewBing;public ViewBindHolder(View view){super(view);}public void setmViewBing(ItemRecyclerviewBinding mViewBing) {this.mViewBing = mViewBing;}public void bind(UserInfo userInfo){mViewBing.setUserInfoExample(userInfo);}
}
...

kt版:

   @NonNulloverride fun onCreateViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewBindHolder? {val inflate: ViewDataBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.context),R.layout.item_recyclerview,parent,false)val viewHolder = ViewBindHolder(inflate)viewHolder.setmViewBing(viewHolder)return RecyclerView.ViewHolder(inflater)}override fun onBindViewHolder(@NonNull holder: ViewBindHolder?, position: Int) {
//        holder.bind(...);//传入的UserInfo}class ViewBindHolder(view: View?) : RecyclerView.ViewHolder(view!!) {private var mViewBing: ItemRecyclerviewBinding? = nullfun setmViewBing(mViewBing: ItemRecyclerviewBinding?) {this.mViewBing = mViewBing}fun bind(userInfo: UserInfo?) {mViewBing!!.setUserInfoExample(userInfo)}}

在onCreateViewHolder中通过DataBindingUtil去获取相应的dataBinding对象,在ViewHolder中进行binding,其余操作与Activity、Fragment差别不大,这里不再赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/679087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB知识点:isempty函数(★★★★☆)判断数组是否为空

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第3章&#xff1a;课后习题讲解中拓展的函数 在讲解第…

OpenCV入门:图像处理的基石

在数字图像处理领域&#xff0c;OpenCV&#xff08;开源计算机视觉库&#xff09;是一个不可或缺的工具。它包含了一系列强大的算法和函数&#xff0c;使得开发者可以轻松地处理图像和视频数据。本文将带你走进OpenCV的世界&#xff0c;了解其基本概念和常见应用。 1. OpenCV简…

uniapp微信小程序开发踩坑日记:Pinia持久化

如果你使用过Pinia&#xff0c;那你应该知道Pinia持久化插件&#xff1a;https://prazdevs.github.io/pinia-plugin-persistedstate/zh/ 但由于官方文档提供的说明并不是针对小程序开发&#xff0c;所以我们在使用这个插件实现uniapp小程序开发中Pinia持久化会出现问题 我在C…

《统计学简易速速上手小册》第3章:概率分布与抽样技术(2024 最新版)

文章目录 3.1 重要的概率分布3.1.1 基础知识3.1.2 主要案例&#xff1a;顾客到访分析3.1.3 拓展案例 1&#xff1a;产品缺陷率分析3.1.4 拓展案例 2&#xff1a;日销售额预测 3.2 抽样方法与推断3.2.1 基础知识3.2.2 主要案例&#xff1a;顾客满意度调查3.2.2 拓展案例 1&#…

蓝桥杯每日一题------背包问题(二)

前言 本次讲解背包问题的一些延申问题&#xff0c;新的知识点主要涉及到二进制优化&#xff0c;单调队列优化DP&#xff0c;树形DP等。 多重背包 原始做法 多重背包的题意处在01背包和完全背包之间&#xff0c;因为对于每一个物品它规定了可选的个数&#xff0c;那么可以考虑…

【JavaEE】_HTML常用标签

目录 1.HTML结构 2. HTML常用标签 2.1 注释标签 2.2 标题标签&#xff1a;h1~h6 2.3 段落标签&#xff1a;p 2.4 换行标签&#xff1a;br 2.5 格式化标签 2.6 图片标签&#xff1a;img 2.7 超链接标签&#xff1a;a 2.8 表格标签 2.9 列表标签 2.10 表单标签 2.10…

C++继承(二):菱形继承、virtual菱形虚拟继承

目录 一、了解菱形继承 二、菱形继承的问题 三、虚拟继承virtual 3.1virtual 3.2虚拟继承解决数据冗余和二义性的原理 四、总结/继承和组合 一、了解菱形继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承 多继承&#xff1a;一个子类有两个或…

python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui

文章目录 用GUI自动控制键盘和鼠标pyautogui 模块鼠标屏幕位置——移动地图——pyautogui.size鼠标位置——自身定位——pyautogui.position()移动鼠标——pyautogui.moveTo拖动鼠标滚动鼠标 键盘按下键盘释放键盘 开始与结束通过注销关闭所有程序 用GUI自动控制键盘和鼠标 在…

【教学类-48-03】202402011“闰年”(每4年一次 2月有29日)世纪年必须整除400才是闰年)

2000-2099年之间的闰年有25次&#xff0c; 背景需求&#xff1a; 已经制作了对称年月的数字提取&#xff0c;和年月日相等的年份提取 【教学类-48-01】20240205对称的“年”和“月日”&#xff08;如2030 0302&#xff09;-CSDN博客文章浏览阅读84次。【教学类-48-01】202402…

专业140+总分410+华南理工大学811信号与系统考研经验华工电子信息与通信,真题,大纲,参考书。

23考研已经落幕&#xff0c;我也成功的上岸华工&#xff0c;回首这一年多的历程&#xff0c;也是有一些经验想和大家分享一下。 首先说一下个人情况&#xff0c;本科211&#xff0c;初试成绩400分。专业课140。 整体时间安排 对于考研&#xff0c;很重要的一环就是时间安排&…

《动手学深度学习(PyTorch版)》笔记8.5

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

python基于flask的网上订餐系统769b9-django+vue

课题主要分为两大模块&#xff1a;即管理员模块和用户模块&#xff0c;主要功能包括个人中心、用户管理、菜品类型管理、菜品信息管理、留言反馈、在线交流、系统管理、订单管理等&#xff1b; 如果用户想要交换信息&#xff0c;他们需要满足双方交换信息的需要。由于时间有限…

使用C#快速创建一个非常实用的桌面应用程序

过节时和我年纪轻轻就一把年纪的弟弟张老二闲聊了许久&#xff0c;发现他对编程产生了一泡浓厚的兴趣&#xff0c;于是我就给他漏了一手C#&#xff0c;做了一个简单的适用于win-x64配置cpu的桌面应用程序。 步骤如下&#xff1a; 1.打开Visual Studio,点击新建项目&#xff0…

C#,泰波拿契数(Tribonacci Number)的算法与源代码

1 泰波拿契数&#xff08;Tribonacci Number&#xff09; 泰波拿契数&#xff08;Tribonacci Number&#xff09;是斐波那契的拓展。 泰波拿契数 (Tribonacci Number) 即把费波拿契数 (Fibonacci Number) 的概念推广至三个数。 2 计算结果 3 源程序 using System; namespace…

Linux笔记之Docker进行镜像备份与迁移

Linux笔记之Docker进行镜像备份与迁移 ——2024-02-11 code review! 文章目录 Linux笔记之Docker进行镜像备份与迁移1. 导出容器文件系统为 tar 归档文件2. 将 tar 归档文件导入为新的 Docker 镜像3. 运行新的 Docker 镜像并创建容器 1. 导出容器文件系统为 tar 归档文件 要导…

前端JavaScript篇之异步编程的实现方式?

目录 异步编程的实现方式&#xff1f;1. 回调函数2. Promise3. Async/Await4. Generator 异步编程的实现方式&#xff1f; 异步编程是处理需要等待的操作的一种方式&#xff0c;比如读取文件、发送网络请求或处理大量数据。在JavaScript中&#xff0c;有几种常见的实现方式&am…

《UE5_C++多人TPS完整教程》学习笔记1 ——《P2 关于本课程(About This Course)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P2 关于本课程&#xff08;About This Course&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&…

ubuntu中尝试安装ros2

首先&#xff0c;ubuntu打开后有个机器人栏目&#xff0c;打开后&#xff0c;有好多可选的&#xff0c;看了半天 ,好像是博客&#xff0c;算了&#xff0c;没啥关系&#xff0c;再看看其他菜单 这些都不是下载链接。先不管&#xff0c;考虑了一下&#xff0c;问了ai&#xff…

数据库恢复

文章目录 前言一、事务1.概念2.定义语句3.ACID特性 二、数据库恢复的必要性1.为什么要进行数据库恢复2.数据库恢复机制的作用 三、数据恢复使用的技术1.数据转储2.登记日志文件 四 、不同故障的数据恢复策略1.事务内部的故障2.系统故障3.介质故障 五、具有检查点的恢复技术1.检…

接口测试--apipost接口断言详解

在做接口测试的时候&#xff0c;会对接口进行断言&#xff0c;一个完整的接口测试&#xff0c;包括&#xff1a;请求->获取响应正文->断言。 一、apipost如何进行断言 apipost的断言设置实在后执行脚本中进行编写的。apipost本身提供了11中断言&#xff1a; apt.asser…