Android DataBinding使用详解

参考:

https://developer.android.google.cn/topic/libraries/data-binding/start.html

https://www.jianshu.com/p/bd9016418af2

DataBinding 是谷歌官方发布的一个框架,顾名思义即为数据绑定,是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。MVVM 相对于 MVP,其实就是将 Presenter 层替换成了 ViewModel 层。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常。

要将应用配置为使用数据绑定,请在应用模块的 build.gradle 文件中添加 dataBinding 元素,如以下示例所示:

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

1 基础入门

打开布局文件,选中根布局的 ViewGroup,按住 Alt + 回车键,点击 “Convert to data binding layout”,就可以生成 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.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

和原始布局的区别在于多出了一个 layout 标签将原布局包裹了起来,data 标签用于声明要用到的变量以及变量类型,要实现 MVVM 的 ViewModel 就需要把数据(Model)与 UI(View)进行绑定,data 标签的作用就像一个桥梁搭建了 View 和 Model 之间的通道。

package com.hongx.databinding.model;

/**
 * @author: fuchenming
 * @create: 2019-12-26 13:47
 */
public class User {
    private String name;
    private String password;
}

在 data 标签里声明要使用到的变量名、类的全路径

    <data>
        <variable
            name="userInfo"
            type="com.hongx.databinding.model.User" />
    </data>

如果 User 类型要多处用到,也可以直接将之 import 进来,这样就不用每次都指明整个包名路径了,而 java.lang.* 包中的类会被自动导入,所以可以直接使用

    <data>
        <import type="com.hongx.databinding.model.User" />

        <variable
            name="userInfo"
            type="User" />
    </data>

如果存在 import 的类名相同的情况,可以使用 alias 指定别名

 	<data>
        <import
            alias="TempUser"
            type="com.hongx.databinding.model.User" />

        <variable
            name="tempUserInfo"
            type="TempUser" />
	</data>          

通过设置 userInfo 的变量值 使 TextView 显示相应的文本

	<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{`姓名:` + userInfo.name,default=zhangsan}" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{`密码:` + userInfo.password,default=123456}" />
    </LinearLayout>

可以在 Activity 中通过 DataBindingUtil 设置布局文件

public class MainActivity extends AppCompatActivity {

    private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        user = new User("fuhongxue", "123456");
        activityMainBinding.setUserInfo(user);
    }
}

如果在TextView中设置id, 可以ActivityMainBinding 直接获取到指定 ID 的控件

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />
    activityMainBinding.tvName.setText("zhangsan");

每个数据绑定布局文件都会生成一个绑定类,ViewDataBinding 的实例名是根据布局文件名来生成,将之改为首字母大写的驼峰命名法来命名,并省略布局文件名包含的下划线。控件的获取方式类似,但首字母小写

也可以通过如下方式自定义 ViewDataBinding 的实例名

  <data class="MyActivityMainBinding">

2 单向数据绑定

实现数据变化自动驱动 UI 刷新的方式有三种:BaseObservable、ObservableField、ObservableCollection

2.1 BaseObservable

一个纯净的 ViewModel 类被更新后,并不会让 UI 自动更新。而数据绑定后,我们自然会希望数据变更后 UI 会即时刷新,Observable 就是为此而生的概念

BaseObservable 提供了 notifyChange() 和 notifyPropertyChanged() 两个方法,前者会刷新所有的值域,后者则只更新对应 BR 的 flag,该 BR 的生成通过注释 @Bindable 生成,可以通过 BR notify 特定属性关联的视图

public class Goods extends BaseObservable {

    //如果是 public 修饰符,则可以直接在成员变量上方加上 @Bindable 注解
    @Bindable
    public String name;

    //如果是 private 修饰符,则在成员变量的 get 方法上添加 @Bindable 注解
    private String details;

    private float price;

    public Goods(String name, String details, float price) {
        this.name = name;
        this.details = details;
        this.price = price;
    }

    public void setName(String name) {
        this.name = name;
        //只更新本字段
        notifyPropertyChanged(com.hongx.databinding.BR.name);
    }

    @Bindable
    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
        //更新所有字段
        notifyChange();
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

}

在 setName() 方法中更新的只是本字段,而 setDetails() 方法中更新的是所有字段

3 双向数据绑定

4 事件绑定

5 使用类方法

8 BindingAdapter

dataBinding 提供了 BindingAdapter 这个注解用于支持自定义属性,或者是修改原有属性。注解值可以是已有的 xml 属性,例如 android:src、android:text等,也可以自定义属性然后在 xml 中使用

例如,对于一个 ImageView ,我们希望在某个变量值发生变化时,可以动态改变显示的图片,此时就可以通过 BindingAdapter 来实现

需要先定义一个静态方法,为之添加 BindingAdapter 注解,注解值是为 ImageView 控件自定义的属性名,而该静态方法的两个参数可以这样来理解:当 ImageView 控件的 url 属性值发生变化时,dataBinding 就会将 ImageView 实例以及新的 url 值传递给 loadImage() 方法,从而可以在此动态改变 ImageView 的相关属性

使用Picasso显示网络图片

public class Image {
    private String url;

    public Image(String url) {
        this.url = url;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    //自定义属性:提供一个静态方法来加载image
    @BindingAdapter({"url"})
    public static void loadImage(ImageView view, String url) {
        Picasso.with(view.getContext()).load(url).into(view);
    }

}
    <data>
        <import type="com.hongx.databinding.model.Image" />
        <variable
            name="image"
            type="Image" />
    </data>
 	 <ImageView
            android:id="@+id/image"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:src="@drawable/ic_launcher_background"
            app:url="@{image.url}" />
       image = new Image("https://www.baidu.com/img/bd_logo1.png?where=super");
        activityMainBinding.setImage(image);

记得添加网络权限

 <uses-permission android:name="android.permission.INTERNET"/>
发布了383 篇原创文章 · 获赞 54 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/hongxue8888/article/details/103713741