databing使用指南

  • 简介
  • 简单使用
  • 双向绑定
  • ListView、RecycleView中的使用
    • . ListView
      • ListView 中数据的简单展示
      • 数据源改变后数据更新方式
    • . RecycleView

简介

随着Android的发展,最初的MVC框架远远无法满足广大_Android猿_ 的需求,进而出现了MVP、MVVM等开发框架,Databing就是Google官方出品的支持MVVM开发的一个依赖库。或许说依赖库不准确,应该说是一整套开发工具和依赖库的集合
今天我们不讲开发框架的问题,我们只是来看一下 databing 的使用

简单使用

  1. 在相关模块下的buidl.gradle中设置对databing的支持
         android {......//MVVM dataBinding 支持dataBinding {enabled = true}......}
  1. gradle.properties中添加下面一句代码开启数据绑定编辑
    android.databinding.enableV2=true
    以上两步完成后我们就可以开心的使用databing的方式进行编码了。
  2. 代码编写
  • 定义 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>节点)和视图元素

数据元素的导入方法

  1. <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>

这里有几种简单的生成规则

  1. 布局中设置ID的view会在Binding类中生成 public final 变量。生成规则为View的ID名首字母小写,移除下划线并大写后面的字母。例如 tv_name会生成tvName。
  2. 对于layout中使用的这些绑定 当我们没有调用binding.setUser(user);的时候是有默认值的。引用类型为null,int为0,boolean为false等

双向绑定

上面只是简单的显示一些数据,一但数据发生变化就监测不到了。别急,下面我们要讲的双向绑定就是解决这个问题的。给个栗子:

从上面的例子我们看出两点

  1. 页面上的输入可以改变数据的值
  2. 数据的改变可以实时的显示在页面上

要实现双向绑定在以上使用的基础上要做以下几点改动

  • 实体类中 这里有两种方法

    • 实体类中的成员变量或者 get方法使用@Bindable注解 (如下代码中name属性)
    • 或者 使用ObservableField定义成员变量 (如下代码中 content 属性)
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中
    @{} 改成@={}即可
    这样就可以实现上面的例子的效果
    有几点想说:
  1. 如果我们只使用了@Bindable 注解而没有在set方法中调用notifyPropertyChanged(BR.name);那么上例中editText内容的改变会引起user实例name值的改变,但是不会更新页面中textView的值。
  2. 我们不仅可以在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);}});
  1. 当我们没有用双向绑定的时,如果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)] 这里有两种方式解决这个问题。

  1. 和之前一样当数据源改变时主动调用 ListAdapter.notifyDataSetChanged()来刷新界面。
  2. 将数据源中的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使用相关推荐

  1. DataBinding的双向绑定实现原理

    " 悄悄咪咪告诉你,DataBinding是怎么实现双向绑定的" 在讲DataBinding之前,有必要讲讲ViewBinding 1.ViewBinding 1) 配置 要使用V ...

  2. android实现双向绑定,Android使用DataBinding实现双向绑定(一)

    前面一段时间学习了一下Android中的DataBinding,但是只是很简单地实现了一下,DataBinding中最强大的地方还没有认真地学习过,有很多地方还不理解.这次,深入学习一下DataBin ...

  3. android——databinding中字符串的拼接处理、TextView显示的值随activity的属性值改变同时改变--LiveData、双向绑定过滤器、监听某个值的改变

    简介 使用的技术是观察者与被观察者的模式,在google推荐的案例中也有使用到,现在我把它封装成一个扩展函数,使得使用更加简单明了 注意 1.在build.gradle添加databinding,在a ...

  4. DataBinding的使用之双向绑定

    DataBinding的双向绑定,可以实现控件和数据的双向绑定,比如在登陆场景下,如果你使用了一个UserModel来保存数据,当你修改UserModel中的字段时,Edittext会自动更新.并且, ...

  5. Android databinding之数据单向与双向绑定详解与使用(三)

    一.介绍 通过前面两篇文档,我们大概了解了databinding的工作方式,view的初始化,recycleview的使用.但是这些UI都离不开数据的填充,数据的修饰. 在说到数据绑定,好多开发者平时 ...

  6. Android开发提升效率之DataBinding——双向绑定

    DataBingding Android开发提升效率之DataBinding--基本使用 Android开发提升效率之DataBinding--进阶开发 Android开发提升效率之DataBindi ...

  7. Android DataBinding双向绑定原理

    Android中的双向绑定是指:将Model设置给View之后,当Model中的数据发生改变时,View显示的内容也会随之改变:当View发生变化时,Model中的数据也会随之改变.双向绑定可以让开发 ...

  8. android dataBinding 与ObservableField实现双向绑定

    1.在build.gradle中添加dataBinding dataBinding{enabled = true } plugins {id 'com.android.application' }an ...

  9. MVC/MVP/MVVM区别——MVVM就是angular,视图和数据双向绑定

    摘自:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html 一.MVC MVC模式的意思是,软件可以分成三个部分. 视图(View):用户界面 ...

最新文章

  1. 聊聊高并发(十六)实现一个简单的可重入锁
  2. AI 重塑 IT的 5 种方式
  3. 关于MVC/P 的简单介绍
  4. pom war jar的区别
  5. 如何发送HTML表单数据
  6. jmeter压力测试_用Jmeter实现对接口的压力测试
  7. 转载 二叉树的创建、遍历、深度、叶子节点数
  8. SAP License:FI学习笔记
  9. istio sidecar流量接管_Istio是个啥?看完此文彻底搞懂(赠书)
  10. CAM350 12.1版本安装
  11. MOSEK安装教程及安装过程遇到的问题
  12. vue鼠标划过移入移出触发方法
  13. IoT全品类全场景来了,但5G时代“大雁群飞”仍需紧盯“服务”
  14. CSS Cascading Style Sheet 级联样式表1
  15. java公路车为什么会被喷,最全指南
  16. 若依(RuoYi-Vue)+Flowable工作流前后端整合教程
  17. #9733;思维导图的30个问答
  18. 记忆尤深的博贺港海鲜
  19. 用Django编写邮箱注册以及验证码
  20. G1D17-研究方向rce45-49不快乐就去敲敲代码

热门文章

  1. Mixly数码管TM1637时钟实验
  2. 【电子技术基础(精华版)】二极管的基础知识
  3. 设计模式--有道笔记的整理
  4. 五脚18.8数码管显示
  5. CSAPP 3e Attack lab
  6. 克隆linux虚拟机密码是多少,Linux虚拟机的克隆及问题处理
  7. IMSI 和 IMEI
  8. MySQL中什么是关系型数据库???
  9. 从32位apk被限制上架的情况来看系统处理
  10. bootstrap框架基础使用