databinding介绍

2024-03-10 19:59
文章标签 介绍 databinding

本文主要是介绍databinding介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、DataBinding介绍

DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源。使其维护起来更加方便,架构更明确简介。所谓的绑定,是绑定什么呢?

  • 数据直接绑定到UI上,数据改变时UI自动更新
  • UI上的数据绑定到变量中,当数据(如EditText中的数据)改变时自动更新

DataBinding非常适合用于MVVM模式中充当View和ViewModel的双向通讯的工具,引入DataBinding之后,我们可以少写很多的例如findViewById()之类的代码。

2、DataBinding使用介绍

2.1 引入DataBinding

要使用DataBinding只需要在build.grade中添加以下代码

android {...dataBinding{enabled = true}...}

2.2 布局文件格式转换

首先我们需要将传统的ViewGroup布局转换为固定的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><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity3"></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

传统布局转换为layout布局也很简单,选中根布局,点击鼠标右键->show Context Action ->convert to data binding layout即可自动生成。生成的布局分为两个部分,数据区布局区,数据区内声明我们所需要用到的变量,布局区和传统的布局一样。

data

标签内进行变量声明和导入等

variable

标签进行变量声明

import

标签导入需要的类

    <data><import type="com.example.model.Book" alias="mBook"/><import type="com.example.Utils.StringUtils"/><variablename="book"type="mBook"/><variablename="books"type="androidx.databinding.ObservableList&lt;String>" /><variablename="bgColor"type="java.lang.String" /></data>

2.3 Activity和Fragment中使用databinding

Activity

public class MainActivity extends AppCompatActivity{private ActivityMainBinding mainBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);...}
}

Fragment

public class TopFragment extends Fragment {private FragmentTopBinding topFragmentBinding;@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {topFragmentBinding = DataBindingUtil.inflate(inflater,R.layout.topfragment,container,false);return topFragmentBinding.getRoot();}
}

注意:

上面的步骤2.2和2.3不能颠倒,因为只有在布局转换成layout样式后,databinding才会根据布局文件的名字自动生成一个对应的binding类,例如ActivityMainBinding和FragmentTopBinding,一般命名方式就是id+binding。如果我们xml文件命名不太规范,不好推测生成的类名,可以在build/generated/data_binding_base_class_source_out目录下查看生成的类。

在这里插入图片描述

生成的ActivityMainBinding类中持有布局文件中一些view的引用,一般来说有三类,根布局,含有**@{}绑定的view**,含有id属性的view。于是我们可以直接通过binding对象去获取视图中的一些view对象,而不需要在经过findViewById()的查找过程。

2.4 数据绑定

在data标签中,variable标签内声明变量名和类型,在布局中通过@{}进行引用,它支持的类型有

  • 引用类型,比如一个类或者对象

  • 基本数据类型,不需要导入对应的包,直接使用即可,由于databinding不会自动做类型转换,因此需要我们自己手动的转换,比如text标签内用String.valueOf()进行转换,rating标签内使用Float.valueOf()进行转换。既然我们可以调用String类中的方法,那么是不是也可以调用其他类中的一些方法呢?当然也是可以的,比如我们定义了一个静态的方法

    public class StringUtils {public static String toUpperCase(String origin){return origin.toUpperCase();}
    }
    

    然后同样在xml文件中通过import 进行导入

    <import type="com.example.Utils.StringUtils"/>
    

    接着就可以像调用String.valueOf()一样去调用它了。

  • 数据集合类型

    • 集合成员的获取方式有get和[ ]两种方式,比如我们传入一个集合books,可以通过"@{books.get(0).author}“或者”@{books[0].author}"来获取它的属性,如果值为null, 可以通过default 来指定其属性。

      android:rating="@{book.rating,default=3.0}"
      

      类似的用法还可以通过??或者是?:来实现, ??会取第一个不为null的值

      android:text="@{book.rating != null ? book.rating : book.defaultRating}"
      
      android:text="@{user.name ?? book.defaultRating}"
      
    • map类型的结构也可以通过get和[ ]两种方式获取,不过需要注意单引号和双引号的成对使用

      "@{map.get(‘zhangsan’)}"或者是’@{map.get(“zhangsan”)}’

        <TextViewandroid:id="@+id/text_publish_house"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{book.publishHouse}"app:layout_constraintBottom_toTopOf="@+id/guideline9"app:layout_constraintStart_toEndOf="@+id/textView7"app:layout_constraintTop_toTopOf="@+id/guideline8" /><TextViewandroid:id="@+id/text_pages"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(book.pages)}"app:layout_constraintBottom_toTopOf="@+id/guideline10"app:layout_constraintStart_toEndOf="@+id/textView8"app:layout_constraintTop_toTopOf="@+id/guideline9" /><RatingBarandroid:id="@+id/ratingBar"android:layout_width="248dp"android:layout_height="62dp"android:numStars="5"android:stepSize="0.5"android:rating="@{book.rating,default=3.0}"app:layout_constraintBottom_toTopOf="@+id/guideline4"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toEndOf="@+id/textView4"app:layout_constraintTop_toTopOf="@+id/guideline2" />

别名

如果我们导入的包名字有冲突,可以在import标签内为其设置一个别名

    <data><import type="com.example.model.Book" alias="mBook"/><import type="com.example.Utils.Book" alias="sBook"/><variablename="book"type="mBook"/></data>

在MainActivity中,导入视图创建ActivityMainBinding对象,通过ActivityMainBinding对象进行数据的注入,对于标签内声明的变量,ActivityMainBinding都会提供一个set方法。

public class MainActivity extends AppCompatActivity {private ActivityMainBinding mBinding;private ArrayList<Book> books;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);Book book = new Book("第一行代码(第三版)","郭霖","人民邮电出版社","2020-4",704,99,"9787115524836",3.0);books.add(book);mBinding.setBook(book);}
}

接下来在Activity中,我们就不需要在写findViewById()之类的代码,直接通过 mBinding就可以对布局中的对象进行引用。

隐式引用属性

在view上引用其他view的属性

<layout ...><data><import type="android.view.View"/></data><RelativeLayout ...><CheckBox android:id="@+id/seeAds" .../><ImageView android:visibility="@{seeAds.checked ? View.VISIBLE : View.GONE}" .../></RelativeLayout>
</layout>

include标签和ViewStub标签

如果我们在视图中通过include标签或者ViewStub标签导入了其他的布局,同样可以通过 dataBinding 来进行数据绑定,首先将需要包含的布局同样改为layout样式

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="com.leavesc.databinding_demo.model.User" /><variablename="userInfo"type="User" /></data><android.support.constraint.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#acc"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:padding="20dp"android:text="@{userInfo.name}" /></android.support.constraint.ConstraintLayout>
</layout>

然后在包含进来的地方将数据传递给它

<includelayout="@layout/view_include"bind:userInfo="@{userInfo}" />

ViewStub的使用方式类似,这里就不叙述了。

2.5 数据对象

要实现数据变化时自动更新UI,有三种方法可以使用,分别是BaseObservable,ObservableField,ObservableCollection,下面一一介绍一下。

  • BaseObservable

自定义一个数据对象,必须继承自BaseObservable,BaseObservable是Android原生的已经封装好的一个类,通过被观察者的方式对数据进行监听,通过注解@Bindable将成员绑定到视图,如果是private类型的成员,则将Bindable加在它的get方法上,视图中就可以引用了。

public class Book extends BaseObservable {// 图片id@Bindablepublic String imageId;// 书名@Bindablepublic String bookName;// 作者@Bindablepublic String author;// 出版社@Bindablepublic String publishHouse;// 出版年@Bindablepublic String publishYear;// 页数@Bindablepublic int pages;// 定价@Bindablepublic double price;// ISBN@Bindablepublic String isbn;// 评分@Bindablepublic Double rating;// 出厂价private double rarePrice;// 私有对象绑定到它的get方法上 @Bindableprivate double getRarePrice(){return this.rarePrice;}...}

那如何在数据更新时自动刷新UI呢?它提供了notifyChange()和notifyPropertyChanged(BR.xx)两个方法进行刷新,前者会刷新所有的成员,后者只会刷新对应的数据成员。示例如下

    public void setBookName(String bookName) {this.bookName = bookName;notifyPropertyChanged(BR.bookName);  // 只更新bookName这一个属性}

这时候如果在其他地方调用了book.setName()这个函数,UI就会被自动更新。上面使用到了BR这个类,它是什么呢,联想到R类,它应该也是系统自动生成的,我们在build/generated/ap_generated_sources/debug/out对应包的目录下可以找到这个类

public class BR {public static final int _all = 0;public static final int author = 1;public static final int name = 2;...
}

在这个类中自动对我们使用Bindable注解的成员进行编号。

监听器回调

当我们在UI中改变控件的某些数据时,如果想要接收到这个改变,那么可以给其添加上一个监听器

        book.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {@Overridepublic void onPropertyChanged(Observable sender, int propertyId) {if (propertyId == BR.author){// TODO}}});
  • ObservableField

    还记得LiveData吗?既然都是观察者模式,那么也可以将需要被观察的数据封装起来,从而不用继承BaseObservale也可以实现数据的绑定,官方提供了对基本类型的封装,如:ObservableBoolean、ObservableByte、ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble 以及 ObservableParcelable ,也可以通过ObservableField<>泛型来申明其它类型。

于是,我们上面的Book类也可以改造成

public class Book {// 图片idpublic ObservableInt imageId;// 书名public ObservableField<String> bookName;// 作者public ObservableField<String> author;// 出版社public ObservableField<String> publishHouse;// 出版年public ObservableField<String> publishYear;// 页数public ObservableInt pages;// 定价public ObservableDouble price;// ISBNpublic ObservableField<String> isbn;// 评分public ObservableFloat rating;...
}

注意:

Book类中必须为每个成员增加上get和set方法,一般我们在其中进行类型转换,比如上面的bookName我们将它转换成String类型再返回,总而言之,不需要向外界暴露出原本的类型。

  • ObservableCollection

observableCollection只是databinding提供的用于替换Java原生的List和Map,分别对应ObservableList和ObservableMap,其用法和原理和ObservableField没有太大的区别。

<variablename="books"type="androidx.databinding.ObservableList&lt;String&lt;" />

2.6 databinding支持的 表达式语法

上面我们就已经使用了字段访问,数组访问[],方法调用,三元运算符等,下面就总结一下xml文件中还支持哪些语法格式。

  • 算术运算符 + - / * %

  • 字符串连接运算符 +

  • 逻辑运算符 && ||

  • 二元运算符 & | ^

  • 一元运算符 + - ! ~

  • 移位运算符 >> >>> <<

  • 比较运算符 == > < >= <=(请注意,< 需要转义为 <)

  • instanceof

  • 分组运算符 ()

  • 字面量运算符 - 字符、字符串、数字、null

  • 类型转换

  • 方法调用

  • 字段访问

  • 数组访问 []

  • 三元运算符 ?:

3、数据的双向绑定

所谓双向绑定,就是当UI上的数据改变时也能更新到变量中,比如我们例子中的Book 星级评分rating, 可以让用户修改评星的同时也能同步到book对象中。使用方式很简单,只需要在原来的绑定方式上加一个=即可。

android:rating="@={book.rating,default=3.0}"

实例演示

。。。

4、 BindingAdapter

当某些属性需要自定义处理逻辑的时候可以使用BindingAdapter, 比如我们可以重新定义TextView的setText方法,让所有的英文全部转换为小写,又例如我们在Book类中保存了图片的id,如果直接在ImageView中直接将图片id传递给ImageView的src属性,图片是不会进行显示的,我们可以通过BindingAdapter重定义ImageView的setImageResource方法,图片就可以显示了。

图片显示例子

1、在Book类中重定义一个静态方法来处理ImageView的setImageResource方法 ,app是一个命名空间,可以不需要。

    @BindingAdapter({"app:imageUrl"})public static void getTransImageView(ImageView imageView, int res){imageView.setImageResource(res);}

2、在布局文件中,ImageView标签内通过app:imageUrl设置图片

        <ImageViewandroid:id="@+id/imageView"android:layout_width="185dp"android:layout_height="344dp"android:layout_marginStart="16dp"android:layout_marginLeft="16dp"app:imageUrl="@{book.imageId}"app:layout_constraintBottom_toTopOf="@+id/guideline2"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView" />

还可以使用BindingAdapter来自定义多个属性,下面看一个例子

public class ImageViewAdapter {/*** 定义多个属性* @param view* @param url* @param placeholder* @param error*/@BindingAdapter(value = {"imageUrl", "placeholder", "error"})public static void loadImage(ImageView view, String url, Drawable placeholder, Drawable error) {RequestOptions options = new RequestOptions();options.placeholder(placeholder);options.error(error);Glide.with(view).load(url).apply(options).into(view);}
}

在布局中使用上面定义的三个属性

<ImageViewandroid:layout_width="100dp"android:layout_height="100dp"android:layout_marginTop="10dp"app:imageUrl="@{`https://goss.veer.com/creative/vcg/veer/800water/veer-136599950.jpg`}"app:placeholder="@{@drawable/icon}"app:error="@{@drawable/error}"/>

此时,三个属性全部使用才能 BindingAdapter 才能正常工作,如果使用了其中的一些属性则不能正常编译通过,那么如何在自定义多个属性而正常使用其中的部分属性呢,@BindingAdapter 注解还有一个参数 requireAll ,requireAll 默认为 true,表示必须使用全部属性,将其设置为 false 就可以正常使用部分属性了,此时,自定义多个属性时要配置 注解 @BindAdapter 的 requireAll 属性为 false,参考如下:

// requireAll = false
@BindingAdapter(value = {"imageUrl", "placeholder", "error"},requireAll = false)
public static void loadImage(ImageView view, String url, Drawable placeholder, Drawable error) {RequestOptions options = new RequestOptions();options.placeholder(placeholder);options.error(error);Glide.with(view).load(url).apply(options).into(view);
}

在布局中,我们只使用到部分属性也不会编译报错了。

5、BindingConversion

有时候,在设置属性值的时候,会发生一些类型不匹配的情况,比如控件RatingBar的rating属性需要设置的float类型的值,但是我们的Book类中rating属性被设置为Double类型了,Book类在多个地方用到,如果要去改类型的话需要修改很多地方,这时就可以直接通过BindingConversion来进行方便的转换了。又比如 android:background 属性接收的是一个 Drawable 当我们在 databinding 的表达式中设置了一个颜色值,此时就需要 @BindingConvert

背景颜色转换例子

假设我们想要直接通过颜色名字设置布局背景,比如通过

mainBinding.setBgColor("skyBlue");

背景文件中是这样使用的

<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><import type="com.example.model.Book" alias="mBook"/><import type="com.example.Utils.StringUtils"/><variablename="book"type="mBook"/><variablename="books"type="androidx.databinding.ObservableList&lt;String>" /><variablename="bgColor"type="java.lang.String" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/text_title"android:background="@{bgColor}"android:layout_width="match_parent"android:layout_height="match_parent"/></layout>

这时候一定会报错,因为background不接受一个String类型的参数,那么我们可以提供一个

函数对其进行转换

@BindingConversionpublic static ColorDrawable convertStringToDrawable(String color){if (color.equals("skyBlue")){return new ColorDrawable(Color.parseColor("#57faff"));}return new ColorDrawable(Color.parseColor("#000000"));
}

databinding会自动查找使用@BindingConversion注解的函数进行转换,能使用@BindingConversion注解的函数有几个要求

  • 必须是静态的
  • 只能由一个参数
  • 被该注解标记的方法,被视为dataBinding的转换方法。

这篇关于databinding介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/795347

相关文章

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)

《MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)》掌握多表联查(INNERJOIN,LEFTJOIN,RIGHTJOIN,FULLJOIN)和子查询(标量、列、行、表子查询、相关/非相关、... 目录第一部分:多表联查 (JOIN Operations)1. 连接的类型 (JOIN Types)

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

Pytorch介绍与安装过程

《Pytorch介绍与安装过程》PyTorch因其直观的设计、卓越的灵活性以及强大的动态计算图功能,迅速在学术界和工业界获得了广泛认可,成为当前深度学习研究和开发的主流工具之一,本文给大家介绍Pyto... 目录1、Pytorch介绍1.1、核心理念1.2、核心组件与功能1.3、适用场景与优势总结1.4、优

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe

Spring Security介绍及配置实现代码

《SpringSecurity介绍及配置实现代码》SpringSecurity是一个功能强大的Java安全框架,它提供了全面的安全认证(Authentication)和授权(Authorizatio... 目录简介Spring Security配置配置实现代码简介Spring Security是一个功能强