DataBinding与LiveData

article/2025/11/11 4:33:27

DataBinding

  • 一、添加配置
  • 二、使用
    • 修改布局文件
    • 具体使用
      • 单向绑定、方法绑定
      • 双向绑定、加载网络图片例子
      • Adapter中使用
      • 使用 ObservableField

一、添加配置

如果需要使用databinding 需要在gradle中添加如下配置

defaultConfig {......//开启dataBindingdataBinding {enabled = true}.......}

二、使用

修改布局文件

选中布局文件根节点,代码提示(使用黄色提示,或者快捷键) Convert to data binding layout
在这里插入图片描述
修改后布局文件如下

<?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><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"tools:context=".study.DataBindingActivity">......</LinearLayout>
</layout>

具体使用

单向绑定、方法绑定

直接上demo代码,具体说明会在代码注释中给出,后面给出总结和注意事项

布局文件

<?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><!--   使用 variable 声明变量 ,此后我们便可以使用 @{} 使用java一样的代码--><variablename="user"type="com.twomonth.twapp.bean.User" /><!--   点击事件     --><variablename="click"type="com.twomonth.twapp.study.DemoActivity.Listener" /></data><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="40dp"tools:context=".study.DemoActivity"><!-- ✅使用 @{} 的形式,就可以使用引用对象中的数据了 --><EditTextandroid:id="@+id/edit_userName"android:layout_width="match_parent"android:layout_height="wrap_content"tools:layout_editor_absoluteX="0dp"tools:layout_editor_absoluteY="145dp"android:text="@{user.userName}"android:hint="请输入用户名"/><EditTextandroid:id="@+id/edit_userPassword"android:layout_width="match_parent"android:layout_height="wrap_content"tools:layout_editor_absoluteX="0dp"tools:layout_editor_absoluteY="210dp"android:text="@{user.passWord}"android:hint="请输入密码"/><!-- ✅使用方法的时候,像下面这样类似于箭头函数 --><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="login"android:onClick="@{()->click.changeUserName()}"android:id="@+id/button"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.userName}"android:id="@+id/tv_userName"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.passWord}"android:id="@+id/tv_password"/><ImageViewandroid:id="@+id/iv_head"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"/></LinearLayout>
</layout>

activity 和 实体类

public class DemoActivity extends AppCompatActivity {ActivityDemoBinding binding;User user;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/*** 将布局文件与activity关联,替代了原来的 setContentView()方法。这样一来省去了手写 findViewById() ,可以通过binding获取控件引用,例如:* binding.button;* binding.editUserName;* binding.getRoot(); 获取顶层布局,在fragment中需要使用这个方法,返回view* @Override*     public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {*         // 在fragment中使用的时候如下*         mFDBinding = DataBindingUtil.inflate(inflater,getLayoutRes(),container,false);*         mFDBinding.getRoot().setBackground(new WaterMarkBgView(getContext(), labels, -30, 15));*         return mFDBinding.getRoot();*     }*/binding = DataBindingUtil.setContentView(this,R.layout.activity_demo);user = new User();user.setUserName("userName");user.setPassWord("pass");user.setHeadImage("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2496571732,442429806&fm=26&gp=0.jpg");/*** 设置user对象之前,需要先在布局文件中使用 variable 标签声明。*/binding.setUser(user);binding.setClick(new Listener());}public class Listener{public void changeUserName(){user.setUserName("改变了用户名");Log.e("twomonth",user.toString());}}
}

public class User {public String userName;private String passWord;public String getHeadImage() {return headImage;}public void setHeadImage(String headImage) {this.headImage = headImage;}private String headImage;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}@Overridepublic String toString() {return "User{" +"userName='" + userName + '\'' +", passWord='" + passWord + '\'' +", headImage='" + headImage + '\'' +'}';}
}

做到这里我们运行demo 变回看到下面这个界面
在这里插入图片描述

我们会发现,几个好处:

  • 不用再写findViewById()这样的样板式代码
  • 创建的user对象中的数据自动填充到了对应的位置,不用再setText()

但是操作一下会发现,LOGIN按钮点击事件是生效了,从日志输出中可以看出user对象已经发生了改变,但是EditText 中的数据却没有发生变化。这是因为我们缺了一个很重要的东西,LiveData,我们应该怎么做,才能让user对象数据发生变化的时候,Editext中的数据会自动更新?


//1.继承 BaseObservable
public class User extends BaseObservable{// 2.使用 @Bindable 注解属性,这里要注意,如果属性是public 的,需要在声明的时候注解//   如果属性是 private 的,需要在 get 方法上注解@Bindablepublic String userName;private String passWord;public String getHeadImage() {return headImage;}public void setHeadImage(String headImage) {this.headImage = headImage;}private String headImage;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;// 3. 在public 属性上注解就可以了,但是在private 属性上仅仅注解是不管用的,还需要在属性值发生改变之后//    通知出去,这里的 BR 是系统生成的notifyPropertyChanged(BR.userName);//    与上面的 notifyPropertyChanged 用法相似,区别是 上面的方法只通知相关的控件刷新内容,//    下面这个方法则是通知所有控件刷新内容//    notifyChange();}@Bindablepublic String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}@Overridepublic String toString() {return "User{" +"userName='" + userName + '\'' +", passWord='" + passWord + '\'' +", headImage='" + headImage + '\'' +'}';}
}

对user对象进行了改造,改造完成后在运行demo 点击LOGIN 按钮,会发现,不仅日志中的输出改变了,对应的 EditextView 和 TextView中的数据也发生了变化,这说明我们的单向绑定已经成功了,这里的单相绑定是指数据实体发生改变的时候,会及时的通知到布局文件,改变显示的内容。

单向绑定的基本用法就是如此了,我们再来看一下双向绑定

双向绑定、加载网络图片例子

上面的demo中我们操作LOGIN 按钮可以改变显示内容,但是反过来,我们改变EditText 中的内容时,却发现,对应的user对象中的userName并不会发生对应的变化。
我们可以修改changeUserName()方法尝试一下:

public class Listener{public void changeUserName(){Log.e("twomonth",user.toString());}}

修改后,我们启动demo 手动改变EditText中的内容,然后点击LOGIN按钮,结果果然,显示在EditText中的内容虽然被我们改变了,但是日志输出中我们会发现,user对象并没有发生变化。
如果要做到Editext中的改变也能及时通知到user对象,就需要双向绑定 将@{} 改成@={},
修改后,我们的布局文件如下:

<?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><!--   使用 variable 声明变量 ,此后我们便可以使用 @{} 使用java一样的代码--><variablename="user"type="com.twomonth.twapp.bean.User" /><!--   点击事件,方法使用     --><variablename="click"type="com.twomonth.twapp.study.DemoActivity.Listener" /></data><LinearLayout...tools:context=".study.DemoActivity"><EditText...android:text="@={user.userName}"android:hint="请输入用户名"/><EditText...android:text="@={user.passWord}"android:hint="请输入密码"/><Button...android:onClick="@{()->click.changeUserName()}"android:id="@+id/button"/><TextView...android:text="@={user.userName}"android:id="@+id/tv_userName"/><TextView...android:text="@={user.passWord}"android:id="@+id/tv_password"/>...</LinearLayout>
</layout>

这个时候我们再去运行demo,向 EditText中输入内容的时候会发现,下面的TextView中的内容同时也在发生变化,点击LOGIN按钮,user从日志中也可以看出,user对象也确确实实发生了改变。至此,双向绑定也就基本实现了。

还有一个imageView 没有处理,怎样能够方便快捷的使用网络图片加载框架,将网络图片也绑定到布局文件中呢:

public class ImageViewDataBinding {// 1写个类,2使用注解声明一个静态方法,3布局文件中使用@BindingAdapter("imageUrl")public static void setImageUrl(ImageView imageView,String imageUrl){Picasso.with(imageView.getContext()).load(imageUrl).placeholder(R.drawable.ic_launcher_background).into(imageView);}
}
<ImageViewandroid:id="@+id/iv_head"android:layout_width="wrap_content"android:layout_height="wrap_content"app:imageUrl="@{user.headImage}"android:layout_gravity="center_horizontal"/>

补充
我们很多时候会碰到

	<import type="com.xxx.xxx.User1" /><importalias="seconedUser"type="com.xxx.xxx.User2" /><variablename="user1"type="User1" /><!--这里引用的是第一个import--><variablename="user2"type="com.xxx.xxx.User2" /><!--这里引用的是第二个import--><variablename="user3"type="seconedUser" /><!--这里引用的是第二个import-->

Adapter中使用

直接上代码,解释和步骤都在里面了

public class DemoAdapter extends RecyclerView.Adapter<DemoAdapter.DemoViewHolder> {@NonNull@Overridepublic DemoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {// 1. 获取databindingxxxBinding demoBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.xxx,parent,false);return new DemoViewHolder(xxxBinding);}@Overridepublic void onBindViewHolder(@NonNull DemoViewHolder holder, int position) {// 3.在这里就可以使用 demoBinding 了}@Overridepublic int getItemCount() {return 0;}static class DemoViewHolder extends RecyclerView.ViewHolder{public DemoViewHolder(@NonNull View itemView) {super(itemView);}// 2.重载构造方法,使用 getRoot 获取根Viewpublic DemoViewHolder(xxxBinding dataBinding){super(dataBinding.getRoot());}}
}

使用 ObservableField

使用 ObservableField 类型的变量,不再需要继承 BaseObservable ,也就不需要在数据刷新的时候进行通知了,相比较而言更加灵活。
官方封装好的还有 ObservableShort、ObservableBoolean、ObservableByte …等一系列!这里就不再赘述了,感兴趣的可以尝试一下。

public class User2{public ObservableField<String> userName;private ObservableField<String> passWord;public ObservableField<String> getUserName() {return userName;}public void setUserName(ObservableField<String> userName) {this.userName = userName;}public ObservableField<String> getPassWord() {return passWord;}public void setPassWord(ObservableField<String> passWord) {this.passWord = passWord;}
}

User2 对象的使用

		user2 = new User2();user2.setUserName(new ObservableField<>("userName"));user2.setPassWord(new ObservableField<>("123456"));// 改变参数的时候 使用ObservableField 的 set 和 get 方法user2.getUserName().set("");user2.getUserName().get();

DataBinding 还提供了 ObservableMap 和 ObservableList
使用描述

		<import type="com.twomonth.twapp.bean.User"/><import type="androidx.databinding.ObservableMap" /><!-- 要用 "&lt;"和 "&gt;",而不是尖括号--><variablename="teacher"type="ObservableMap&lt;String,User&gt;" /><import type="androidx.databinding.ObservableList" /><variablename="student"type="ObservableList&lt;String&gt;" /><EditTextandroid:id="@+id/edit_userName"android:layout_width="match_parent"android:layout_height="wrap_content"tools:layout_editor_absoluteX="0dp"tools:layout_editor_absoluteY="145dp"android:text='@{teacher["wang"]}'android:hint="请输入用户名"/><EditTextandroid:id="@+id/edit_userPassword"android:layout_width="match_parent"android:layout_height="wrap_content"tools:layout_editor_absoluteX="0dp"tools:layout_editor_absoluteY="210dp"android:text="@={student[0]}"android:hint="请输入密码"/>
ObservableMap<String,User> observableMap = new ObservableArrayMap<>();observableMap.put("wang",new User());binding.setTeacher(observableMap);

http://chatgpt.dhexx.cn/article/aygk046V.shtml

相关文章

ViewModel+LiveData+DataBinding

1 ViewModel ViewModel要解决的问题 瞬态数据的丢失异步调用的内存泄露类膨胀提高维护难度和测试难度 ViewModel是介于视图和数据模型之间的桥梁&#xff0c;使数据和视图分离的同时还能通信。 2 LiveData ViewModel中可以存储普通数据&#xff0c;LiveDate数据 普通数据…

【Jetpack】LiveData 架构组件 ( LiveData 简介 | LiveData 使用方法 | ViewModel + LiveData 示例 )

文章目录 一、LiveData 简介二、LiveData 使用方法三、ViewModel LiveData 简单示例1、ViewModel LiveData 代码2、Activity 组件代码3、运行效果展示 四、ViewModel LiveData Fragment 通信示例1、ViewModel LiveData 代码2、Activity 组件代码Activity 代码布局文件 3、…

LiveData详细分析

目录介绍 01.LiveData是什么东西02.使用LiveData的优势03.使用LiveData的步骤04.简单使用LiveData05.observe()和observerForever()06.LiveData原理介绍07.observe订阅源码分析08.setValue发送源码分析09.observeForever源码10.LiveData源码总结 00.使用LiveData实现bus事件总…

LiveData+Room

文章目录 LiveData1.LiveData的作用2.LiveData的特点3.LiveData与ViewModel(无参数)的结合4.LiveData与ViewModel(有参数)的结合5.map()和switchMap()5.0 map()和switchMap()的作用5.1map()5.11没带ViewModel版5.12带ViewModel版 5.2switchMap() Room1.Room的定义2.Room的三个组…

Android架构组件(二)——LiveData

Android架构组件&#xff08;二&#xff09;——LiveData 上一篇文章讲到了Android架构组件之一Lifecycle组件&#xff08;Android 架构组件&#xff08;一&#xff09;——Lifecycle-Aware Components&#xff0c;现在我们再来看看另一个成员LiveData。 定义 简单地说&#xf…

Android LiveData 使用详解

说在前面 本次推出 Android Architecture Components 系列文章&#xff0c;目前写好了四篇&#xff0c;主要是关于 lifecycle&#xff0c;livedata 的使用和源码分析&#xff0c;其余的 Navigation&#xff0c; Paging library&#xff0c;Room&#xff0c;WorkMannager 等春节…

由浅入深,详解 LiveData 的那些事

引言 关于LiveData,在2022尾声的今天&#xff0c;从事 Android 开发的小伙伴一定不会陌生。相应的&#xff0c;关于 LiveData 解析与使用的文章更是数不胜数&#xff0c;其中不乏优秀的创作者&#xff0c;在众多的文章以及前辈面前&#xff0c;本篇也不敢妄谈能写的多么深入,易…

LiveData的原理和使用

LiveData Livedata是什么&#xff1f;它的作用是什么&#xff1f;我们能用它来干什么&#xff1f; 首先&#xff0c;LiveData是一种可观察的数据存储类。这句话可以看成两个部分&#xff0c;一个是可观察的类&#xff0c;另一个是数据存储的类。 LiveData 是可以被观察的&am…

python电子书合集

Python电子书合集 小编最早接触的编程语言是C&#xff0c;决心走上编程之路的是JavaScript&#xff0c;后来入职靠的Java&#xff0c;后来发现还有一门短小精悍的语言叫——Python。 本来以为是一门新语言&#xff0c;结果才发现是自己out了&#xff0c;没想到这门语言比小编还…

《Python Cookbook》(中文第三版):电子书

《Python Cookbook&#xff08;第3版&#xff09;中文版》介绍了Python应用在各个领域中的一些使用技巧和方法&#xff0c;其主题涵盖了数据结构和算法&#xff0c;字符串和文本&#xff0c;数字、日期和时间&#xff0c;迭代器和生成器&#xff0c;文件和I/O&#xff0c;数据编…

python编程入门电子书-《Python编程 从入门到实践》高清电子书免费下载

今天给大家分享一本书 获取方式 公众号后台回复 Python基础 获取百度网盘下载链接 书籍简介 本书旨在让你成为优秀的程序员&#xff0c;具体地说&#xff0c;是优秀的Python程序员。通过阅读本书&#xff0c;你将迅速掌握编程概念&#xff0c;打下坚实的基础&#xff0c;并…

【小沐学Python】Python实现在线电子书制作(MkDocs + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建新项目4、添加页面5、编辑导航页6、设置主题7、更改图标图标8、构建网站9、部署9.1 准备github项目9.2 注册登录Read the Docs9.3 导入github项目到 Read the Docs 10、Markdown语法10.1 横线10.2 标题10.3 段落10.4 文字高亮10.5 换行10.6 斜体…

超全的Python完全版电子书——从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单的…

【小沐学Python】Python实现在线电子书制作(Sphinx + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建测试工程4、项目文件结构5、编译为本地文件6、编译为http服务7、更改样式主题8、支持markdown9、修改文档显示结构10、项目托管到github11、部署到ReadtheDocs结语 1、简介 Sphinx 是一个 文档生成器 &#xff0c;您也可以把它看成一种工具&…

python编程入门电子书-Python3零基础教材电子书合集

Python3零基础教材电子书合集&#xff0c;传送门&#xff1a;https://www.52pojie.cn/thread-676318-1-1.html 一、《Python编程从入门到实践》 链接&#xff1a;https://pan.baidu.com/s/1o9wJq0y 密码&#xff1a;12od 这书楼主现在也在看&#xff0c;讲的很细&#xff0c;…

学习Python必看的经典书籍(附电子书)

哈喽&#xff0c;我是牙儿 今天给大家推荐几本经典的Python书籍 一起来看看都有哪些吧~ 1 《Python学习手册&#xff08;第4版&#xff09;》 这本书全面、深入地介绍了 Python 语言&#xff0c;不管你是编程新手还是 Python 初学者&#xff0c;它将帮助你快速实现使用 Pyt…

超全的Python完全版电子书.pdf !从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单…

python入门经典电子书-推荐6本学习Python的免费电子书

便宜并不是没好货&#xff0c;这里的一些书籍已经被很多大学作为课本来使用&#xff0c;比如麻省理工的计算机科学与编程入门课程&#xff0c;加利福尼亚大学的编程思想课程都用到了下面的某(几)本书籍。 简明 简明 Python 教程是Swaroop C.H. 教授为Python初学者写的一本书。…

Python 开源电子书资源

转载自公众号&#xff1a;Mocun6 昨天给大伙儿送了书&#xff0c;留言区的篇幅占了整篇文章的一半&#xff0c;看来大家都想好&#xff08;把&#xff09;好&#xff08;我&#xff09;学&#xff08;掏&#xff09;习&#xff08;空&#xff09;。今天不送纸质书了&#xff0c…

100多本python书,免费电子版下载

推荐&#xff1a; 1、Coffee Break Python Slicing: 24 Workouts to Master Slicing in Python, Once and for All 切片&#xff08;Slicing&#xff09;是 Python 里非常有用的一个功能&#xff0c;属于 Python 开发人员最基本的技能之一。 如果你是初学者而且想了解 Slicin…