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.hqwc.cn/news/465082.html

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

相关文章

渗透专用虚拟机(公开版)

0x01 工具介绍 okfafu渗透虚拟机公开版。解压密码&#xff1a;Mrl64Miku&#xff0c;压缩包大小&#xff1a;15.5G&#xff0c;解压后大小&#xff1a;16.5G。安装的软件已分类并在桌面中体现&#xff0c;也可以使用everything进行查找。包含一些常用的渗透工具以及一些基本工…

如何入门AI Agent?

随着chatgpt问世&#xff0c;大模型已经在加速各行各业的变革&#xff0c;这是我之前对AI Agent行业的粗浅判断。 下面给大家介绍一下如何制作AI Agent&#xff0c;我会用我开发的全赞AI为例子进行简要的介绍&#xff0c;下面是一种工具型AI Agent的框架图 这是一个大量使用工具…

探索海洋世界,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建海洋场景下海洋生物检测识别分析系统

前面的博文中&#xff0c;开发实践过海底相关生物检测识别的项目&#xff0c;对于海洋场景下的海洋生物检测则很少有所涉及&#xff0c;这里本文的主要目的就是想要开发构建基于YOLOv8的海洋场景下的海洋生物检测识别系统。 首先看下实例效果&#xff1a; 简单看下实例数据情况…

解决 postman测试接口报404 Not Found

JDK版本&#xff1a;jdk17 IDEA版本&#xff1a;IntelliJ IDEA 2022.1.3 文章目录 问题描述原因分析解决方案 问题描述 当我使用postman测试接口时&#xff0c;报了 404 Not Found 的错误&#xff0c;报错截图如下所示 但我的后端程序中已经定义了该接口&#xff0c;如下所示 …

MySQL-----DCL基础操作

▶ DCL简介 DCL英文全称是Data ControlLanguage(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 DCL--管理用户 ▶ 查询用户 use mysql; select * from user; ▶ 创建用户 ▶ 语法 create user 用户名主机名 identified by 密码 设置为在任意主机上访问…

Netty应用(七) 之 Handler Netty服务端编程总结

目录 15.Handler 15.1 handler的分类 15.1.1 按照方向划分 15.1.2 handler的结构 15.2 输入方向ChannelInboundHandlerAdapter 15.2.1 输出方向Handler的顺序 15.2.2 多个输入方向Handler之间的数据传递 15.2.2.1 handler消失了 15.2.2.2 手动编写netty提供的new Strin…

C语言之预处理详解

目录 1. 预定义符号2. #define定义常量3. #define定义宏练习 4. 带有副作用的宏参数5. 宏替换的规则6. 宏函数的对比宏和函数的一个对比 7. #和###运算符##运算符 8. 命名约定9. #undef10. 命令行定义11. 条件编译常见的条件编译 12. 头文件的包含头文件的包含方式库文件包含嵌…

【数据结构】11 堆栈(顺序存储和链式存储)

定义 可认为是具有一定约束的线性表&#xff0c;插入和删除操作都在一个称为栈顶的端点位置。也叫后入先出表&#xff08;LIFO&#xff09; 类型名称&#xff1a;堆栈&#xff08;STACK&#xff09; 数据对象集&#xff1a; 一个有0个或者多个元素的有穷线性表。 操作集&#…

【后端高频面试题--Mybatis篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Mybatis篇 什么是Mybatis&#xff1f;Mybatis的优缺点&#xff1f;Mybatis的特点…

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

前言 之前求的是在特点情况下选择一些物品让其价值最大&#xff0c;这里求的是方案数以及具体的方案。 背包问题求方案数 既然要求方案数&#xff0c;那么就需要一个新的数组来记录方案数。动态规划步骤如下&#xff0c; 定义dp数组 第一步&#xff1a;缩小规模。考虑n个物品…

锐捷(十九)锐捷设备的接入安全

1、PC1的IP地址和mac地址做全局静态ARP绑定; 全局下&#xff1a;address-bind 192.168.1.1 mac&#xff08;pc1&#xff09; G0/2:ip verify source port-securityarp-check 2、PC2的IP地址和MAC地址做全局IPMAC绑定&#xff1a; Address-bind 192.168.1.2 0050.7966.6807Ad…

144. 二叉树的前序遍历

给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输出&a…