DataBinding使用指南(一)DataBinding基本使用,双向绑定,ListView RecycleView使用
databing使用指南
- 简介
- 简单使用
- 双向绑定
- ListView、RecycleView中的使用
- . ListView
- ListView 中数据的简单展示
- 数据源改变后数据更新方式
- . RecycleView
简介
随着Android的发展,最初的MVC框架远远无法满足广大_Android猿_ 的需求,进而出现了MVP、MVVM等开发框架,Databing就是Google官方出品的支持MVVM开发的一个依赖库。或许说依赖库不准确,应该说是一整套开发工具和依赖库的集合
今天我们不讲开发框架的问题,我们只是来看一下 databing 的使用
简单使用
- 在相关模块下的
buidl.gradle
中设置对databing的支持
android {......//MVVM dataBinding 支持dataBinding {enabled = true}......}
- 在
gradle.properties
中添加下面一句代码开启数据绑定编辑
android.databinding.enableV2=true
以上两步完成后我们就可以开心的使用databing的方式进行编码了。 - 代码编写
- 定义 ViewModel类定义 ViewModel类
public class User extends BaseObservable {private String name;private String sex;private int age;public User(String name, String sex, int age) {this.name = name;this.sex = sex;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
这里的user类和我们以前定义的实体类并没有任何的区别。
- xml中绑定数据
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><!-- 数据元素节点,定义导入我们要绑定的数据元素 --><data><variablename="user"type="com.caozy.demo1.bean.User" /></data><!-- 视图元素节点 --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:text="@{user.name}" /><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:text="@{user.sex}" /><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:text="@{String.valueOf(user.age)}" /><Buttonandroid:id="@+id/btn_1"android:layout_width="match_parent"android:layout_height="50dp"android:text="Click Me !" /><Buttonandroid:id="@+id/btn_2"android:layout_width="match_parent"android:layout_height="50dp"android:text="btn2"/></LinearLayout>
</layout>
在这里xml文件中的根标签不再是一个容器,而是变成了<layout></layout>
并且在头部添加了<data></data>
标签,和java文件中的import有类似的作用。我们一般创建的xml文件的根标签都是容器,这里有一个快捷键可以使用,将光标放在根标签处使用快捷键 Mac (⌥ + Enter)
wimdows(Alt + Enter)
你会看到如下提示
选择 Convert to data binding layout
可以很快捷的将普通的xml布局文件转换成 dataBinding 需要的xml形式
data binding layout 有两部分 数据元素(即<data></data>
节点)和视图元素
数据元素的导入方法
<variable>
标签直接导入。
<data><variablename="user"type="com.caozy.demo1.bean.User" /><variablename="user2"type="com.caozy.demo1.samename.User"/></data>
代码中 name 是我们控件绑定数据时的实例引用,类似我们对java实例的应用。
type就是我们要导入的数据类型
2. 结合 <import>
标签导入
<data><import type="com.caozy.demo1.bean.User" /><!-- 取了别名的 import --><import type="com.caozy.demo1.samename.User"alias="user1"/><variablename="user"type="User" /><variablename="user1"type="user1"/></data>
如上代码中,如果在不同包中有同名的类,你可以在导入这个类时取一个别名,<variable>
中type用这个别名就可以了。
数据元素的绑定
布局中使用@{}
语法在属性中绑定数据。
android:text="@{user.name}"
这里就是将text属性绑定为user的name属性
- activity中代码
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);User user = new User("张三", "男", 18);binding.setUser(user);}
这里可能会有很多人奇怪ActivityMainBinding
类的由来。这个类当你将xml转换成data binding layout 的时候就自动生成了。默认情况下生成的Binding类名是根据布局文件名称生成的,大写字母开头,移除下划线并大写后面的字母最后加上“Binding”后缀。Binding类位于包com.caozy.demo1.databinding.ActivityMainBinding
,当然这是在build文件夹下。也可以指定Binding类的名字,看代码
<data class="Main"></data>或<data class=".Main"></data>或<data class="com.caozhy.Main"></data>
这里有几种简单的生成规则
- 布局中设置ID的view会在Binding类中生成 public final 变量。生成规则为View的ID名首字母小写,移除下划线并大写后面的字母。例如 tv_name会生成tvName。
- 对于layout中使用的这些绑定 当我们没有调用
binding.setUser(user);
的时候是有默认值的。引用类型为null,int为0,boolean为false等
双向绑定
上面只是简单的显示一些数据,一但数据发生变化就监测不到了。别急,下面我们要讲的双向绑定就是解决这个问题的。给个栗子:
从上面的例子我们看出两点
- 页面上的输入可以改变数据的值
- 数据的改变可以实时的显示在页面上
要实现双向绑定在以上使用的基础上要做以下几点改动
- 实体类中 这里有两种方法
- 实体类中的成员变量或者 get方法使用
@Bindable
注解 (如下代码中name属性) - 或者 使用
ObservableField
定义成员变量 (如下代码中 content 属性)
- 实体类中的成员变量或者 get方法使用
public class User extends BaseObservable {//使用 @Bindable 注解实现双向绑定@Bindableprivate String name;private String sex;//使用 ObservableField 定义 成员变量实现双向绑定private ObservableField<String> content = new ObservableField<>();public ObservableField<String> getContent() {return content;}public void setContent(ObservableField<String> content) {this.content = content;}//@Bindable //也可以在get方法上使用 注解public String getName() {return name;}public void setName(String name) {this.name = name;//更新页面数据notifyPropertyChanged(BR.name);}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}
}
注意: 使用 ObservableField时有一点需要注意,定义的属性一定要调用new ObservableField<>()
初始化
这里对于 基本数据类型 和 list map 等都有对于的Observable类可供使用
- xml中
将@{}
改成@={}
即可
这样就可以实现上面的例子的效果
有几点想说:
- 如果我们只使用了
@Bindable
注解而没有在set方法中调用notifyPropertyChanged(BR.name);
那么上例中editText内容的改变会引起user实例name值的改变,但是不会更新页面中textView的值。 - 我们不仅可以在user实体类的set方法中调用
notifyPropertyChanged(BR.name)
也可以在任何我们需要的地方用user类的对象调用这一方法
再给个栗子:
这里就是将user类中的setName
方法中的notifyPropertyChanged(BR.name)
代码去掉,Activity中添加button的点击代码
binding.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//更新页面中user的name属性user.notifyPropertyChanged(BR.name);}});
- 当我们没有用双向绑定的时,如果user的数据发生了变化,我们也可以再次调用
binding.setUser(user);
方法更新页面数据,每次调用binding.setUser(user);
都会进行页面数据的更新
ListView、RecycleView中的使用
. ListView
ListView 中数据的简单展示
activity的代码跟你平时是一样的。xml的代码还是那个样子,只是 item的xml改成dataBinding layout 就可以了。
我们主要看一下Adapter
的代码
public class ListAdapter extends BaseAdapter {private Context context;private List<User> users;public ListAdapter(Context context, List<User> users) {this.context = context;this.users = users;}@Overridepublic int getCount() {return users.size();}@Overridepublic User getItem(int position) {return users.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ItemListBinding binding;if (convertView == null) {//这里的最后一个参数必须为 falsebinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_list, parent, false);convertView = binding.getRoot();} else {binding = DataBindingUtil.getBinding(convertView);}binding.setUser(getItem(position));
// binding.setVariable(BR.user, getItem(position));return convertView;}
}
Adapter的代码暂时就这些了。
有的朋友会说:”你这个为什么没有用 ViewHolder呀?”。其实,dataBinding 已经对这方面做了处理。 不信你跟踪DataBindingUtil.getBinding(convertView);
这行代码进去。跟踪两步,你最终会发现这么一句代码return (ViewDataBinding) v.getTag(R.id.dataBinding);
是不是这就很熟悉了。
数据源改变后数据更新方式
经过上面第一步,你一经展示出了list的数据。有些人可能会发现有问题,不要着急,因为确实有问题,即使没有问题经过下面的操作也会发现问题。
修改数据源,并且不去调用我们通常调用的ListAdapter.notifyDataSetChanged();
此时点击listview中的某一项,会发现程序闪退。对于这个问题我们并不陌生。报错信息为java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131165264, class android.widget.ListView) with Adapter(class com.caozy.listview1demo.ListAdapter)]
这里有两种方式解决这个问题。
- 和之前一样当数据源改变时主动调用
ListAdapter.notifyDataSetChanged()
来刷新界面。 - 将数据源中的List替换成
ObservableList
。这个接口继承 List接口。所以用法和List一样,只是多了一个数据变化的监听OnListChangedCallback
;只是一个接口所以DataBinding也提供了可供实例化的ObservableArrayList
,这个类继承ArrayList。我们俩看下adapter的代码,
public class ListAdapter extends BaseAdapter {private Context context;private ObservableList<User> users;public ListAdapter(Context context, ObservableList<User> users) {this.context = context;this.users = users;//设置数据变化监听users.addOnListChangedCallback(new ListChangeListener());}@Overridepublic int getCount() {return users.size();}@Overridepublic User getItem(int position) {return users.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ItemListBinding binding;if (convertView == null) {//这里的最后一个参数必须为 falsebinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_list, parent, false);convertView = binding.getRoot();} else {binding = DataBindingUtil.getBinding(convertView);}binding.setUser(getItem(position));
// binding.setVariable(BR.user, getItem(position));return convertView;}/*** 数据变化监听*/private class ListChangeListener extends ObservableList.OnListChangedCallback {@Overridepublic void onChanged(ObservableList sender) {ListAdapter.this.notifyDataSetChanged();}@Overridepublic void onItemRangeChanged(ObservableList sender, int positionStart, int itemCount) {ListAdapter.this.notifyDataSetChanged();}@Overridepublic void onItemRangeInserted(ObservableList sender, int positionStart, int itemCount) {ListAdapter.this.notifyDataSetChanged();}@Overridepublic void onItemRangeMoved(ObservableList sender, int fromPosition, int toPosition, int itemCount) {ListAdapter.this.notifyDataSetChanged();}@Overridepublic void onItemRangeRemoved(ObservableList sender, int positionStart, int itemCount) {ListAdapter.this.notifyDataSetChanged();}}
}
我们看到代码并没有多大的变化,只是将list替换成ObservableList并对其添加数据监听。这样就无需在数据变化时调用ListAdapter.notifyDataSetChanged()
。
. RecycleView
其他都和平时的使用是一样的。我们就来看一下adapter中代码
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.CzyViewHolder> {ObservableList<User> mList;public RecycleViewAdapter(ObservableList<User> mList) {this.mList = mList;mList.addOnListChangedCallback(new CzyOnListChangeCallback());}@NonNull@Overridepublic CzyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {//这里的第四个参数必须为 false 这在GoogleItemRecycleViewBinding binding = DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_recycle_view, viewGroup, false);return new CzyViewHolder(binding.getRoot());}@Overridepublic void onBindViewHolder(@NonNull CzyViewHolder czyViewHolder, int i) {ItemRecycleViewBinding binding = DataBindingUtil.getBinding(czyViewHolder.itemView);binding.setUser(mList.get(i));}@Overridepublic int getItemCount() {return mList.size();}class CzyViewHolder extends RecyclerView.ViewHolder {public CzyViewHolder(@NonNull View itemView) {super(itemView);}}//数据变化监听class CzyOnListChangeCallback extends ObservableList.OnListChangedCallback {@Overridepublic void onChanged(ObservableList sender) {}@Overridepublic void onItemRangeChanged(ObservableList sender, int positionStart, int itemCount) {RecycleViewAdapter.this.notifyItemRangeChanged(positionStart, itemCount);}@Overridepublic void onItemRangeInserted(ObservableList sender, int positionStart, int itemCount) {RecycleViewAdapter.this.notifyItemRangeInserted(positionStart, itemCount);}@Overridepublic void onItemRangeMoved(ObservableList sender, int fromPosition, int toPosition, int itemCount) {RecycleViewAdapter.this.notifyItemMoved(fromPosition, toPosition);}@Overridepublic void onItemRangeRemoved(ObservableList sender, int positionStart, int itemCount) {RecycleViewAdapter.this.notifyItemRangeRemoved(positionStart, itemCount);}}
}
这篇文章我们主要讲了一下dataBinding对控件和list视图等进行数据绑定。我们发现仅仅简单的绑定了文字,对一些复杂的数据处理我们将在下一章进行讲解。
如:网络图片的加载等。
DataBinding使用指南(一)DataBinding基本使用,双向绑定,ListView RecycleView使用相关推荐
- DataBinding的双向绑定实现原理
" 悄悄咪咪告诉你,DataBinding是怎么实现双向绑定的" 在讲DataBinding之前,有必要讲讲ViewBinding 1.ViewBinding 1) 配置 要使用V ...
- android实现双向绑定,Android使用DataBinding实现双向绑定(一)
前面一段时间学习了一下Android中的DataBinding,但是只是很简单地实现了一下,DataBinding中最强大的地方还没有认真地学习过,有很多地方还不理解.这次,深入学习一下DataBin ...
- android——databinding中字符串的拼接处理、TextView显示的值随activity的属性值改变同时改变--LiveData、双向绑定过滤器、监听某个值的改变
简介 使用的技术是观察者与被观察者的模式,在google推荐的案例中也有使用到,现在我把它封装成一个扩展函数,使得使用更加简单明了 注意 1.在build.gradle添加databinding,在a ...
- DataBinding的使用之双向绑定
DataBinding的双向绑定,可以实现控件和数据的双向绑定,比如在登陆场景下,如果你使用了一个UserModel来保存数据,当你修改UserModel中的字段时,Edittext会自动更新.并且, ...
- Android databinding之数据单向与双向绑定详解与使用(三)
一.介绍 通过前面两篇文档,我们大概了解了databinding的工作方式,view的初始化,recycleview的使用.但是这些UI都离不开数据的填充,数据的修饰. 在说到数据绑定,好多开发者平时 ...
- Android开发提升效率之DataBinding——双向绑定
DataBingding Android开发提升效率之DataBinding--基本使用 Android开发提升效率之DataBinding--进阶开发 Android开发提升效率之DataBindi ...
- Android DataBinding双向绑定原理
Android中的双向绑定是指:将Model设置给View之后,当Model中的数据发生改变时,View显示的内容也会随之改变:当View发生变化时,Model中的数据也会随之改变.双向绑定可以让开发 ...
- android dataBinding 与ObservableField实现双向绑定
1.在build.gradle中添加dataBinding dataBinding{enabled = true } plugins {id 'com.android.application' }an ...
- MVC/MVP/MVVM区别——MVVM就是angular,视图和数据双向绑定
摘自:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html 一.MVC MVC模式的意思是,软件可以分成三个部分. 视图(View):用户界面 ...
最新文章
- 聊聊高并发(十六)实现一个简单的可重入锁
- AI 重塑 IT的 5 种方式
- 关于MVC/P 的简单介绍
- pom war jar的区别
- 如何发送HTML表单数据
- jmeter压力测试_用Jmeter实现对接口的压力测试
- 转载 二叉树的创建、遍历、深度、叶子节点数
- SAP License:FI学习笔记
- istio sidecar流量接管_Istio是个啥?看完此文彻底搞懂(赠书)
- CAM350 12.1版本安装
- MOSEK安装教程及安装过程遇到的问题
- vue鼠标划过移入移出触发方法
- IoT全品类全场景来了,但5G时代“大雁群飞”仍需紧盯“服务”
- CSS Cascading Style Sheet 级联样式表1
- java公路车为什么会被喷,最全指南
- 若依(RuoYi-Vue)+Flowable工作流前后端整合教程
- #9733;思维导图的30个问答
- 记忆尤深的博贺港海鲜
- 用Django编写邮箱注册以及验证码
- G1D17-研究方向rce45-49不快乐就去敲敲代码