DataBinding的用法

首先,为什么要使用DataBinding?

  • 一般写法findViewById 罗里吧嗦,写到想吐
  • ButterKnife 代替 解放findViewById
  • DataBinding数据和UI低耦合

一、简介:

The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.

DataBinding 是一个支持库,它允许您使用声明性格式而不是以编程方式将应用程序中的UI组件绑定到应用程序中的数据源。

1.1优点:

布局文件中的绑定组件允许您在Activtiy中删除许多UI框架调用,使其更简单,更易于维护。这还可以提高应用程序的性能,并有助于防止内存泄漏和空指针异常。

常用方式:

TextView textView = findViewById(R.id.sample_text);
textView.setText(viewModel.getUserName());

使用databinding

<TextView
    android:text="@{viewmodel.userName}" />

是不是简单了很多?

1.2 避免空指针异常

生成的数据绑定代码会自动检查null值并避免空指针异常。例如,在表达式中@{user.name},如果 user为null,user.name则为其分配其默认值null。如果您引用user.ageage,其中age是类型int,则数据绑定使用默认值0

二、环境配置:

要开始使用数据绑定,请从Android SDK管理器中的Support Repository下载库。有关更多信息,请参阅更新IDE和SDK工具。要将应用程序配置为使用数据绑定,请app模块中的 build.gradle 文件下在将dataBinding该元素添加到文件中,如以下示例所示:

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

三、绑定表达式

DataBinding 自动生成将布局中的视图与数据对象绑定所需的类。数据绑定布局文件略有不同,以根标记开头, layout后跟data元素和view根元素。此视图元素是您的根在非绑定布局文件中的位置。以下代码显示了一个示例布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

其中的user变量data描述了可在此布局中使用的属性。

<variable name="user" type="com.example.User" />

布局中的表达式使用“ @{}”语法写入属性中。这里,TextView文本设置为user变量的 firstName属性:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}" />

我们现在假设你有一个普通的对象来描述User 实体:

public class User {
  public final String firstName;
  public final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

这种类型的对象具有永不改变的数据。在应用程序中,通常会读取一次并且之后不会更改的数据。也可以使用遵循一组约定的对象,例如访问器方法的用法,如以下示例所示:

public class User {
  private final String firstName;
  private final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
  public String getFirstName() {
      return this.firstName;
  }
  public String getLastName() {
      return this.lastName;
  }
}

从数据绑定的角度来看,这两个类是等价的。@{user.firstName}用于该android:text 属性的表达式访问前一类中的字段firstName和 后一类中的getFirstName() 方法。或者,firstName()如果存在该方法,也可以解决。

四、绑定数据

为每个布局文件生成绑定类。默认情况下,类的名称基于布局文件的名称,将其转换为Pascal大小写并向其添加Binding后缀。上面的布局文件名是 activity_main.xml相应生成的类 MainActivityBinding。此类包含布局属性(例如,user变量)到布局视图的所有绑定,并知道如何为绑定表达式指定值。建议绑定的推荐方法是在扩展布局时执行此操作,如图所示在以下示例中:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
   User user = new User("Test", "User");
   binding.setUser(user);
}

在运行时,应用程序在UI中显示Test用户。或者,您可以使用a获取视图LayoutInflater,如以下示例所示:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

如果您在a FragmentListViewRecyclerView适配器中使用数据绑定项,则可能更喜欢使用 inflate()) 绑定类或 DataBindingUtil类的方法,如以下代码示例所示:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate (layoutInflater, R.layout.list_item, viewGroup, false

五、表达式运算符和关键字

表达式运算符关键字和代码中很相似,很好理解,直接看吧。。

  • 数学的 + - / * %
  • 字符串连接 +
  • 合乎逻辑 && ||
  • 二进制 & | ^
  • 一元 + - ! ~
  • 转移 >> >>> <<
  • 对照 == > < >= <=
  • instanceof
  • 分组 ()
  • 文字 - 字符,字符串,数字, null
  • 方法调用
  • 现场访问
  • 数组访问 []
  • 三元运算符 ?:

举例:

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
  • ??空结合运算 这个比较特殊,值得注意下
  android:text="@{user.displayName ?? user.lastName}"

嘛意思呢? 意思就是判断user.displayName是否为null ,不为null,user.displayName,为null,则user.lastName,等价于以下代码:

  android:text="@{user.displayName != null ? user.displayName : user.lastName}"

六、集合

[]为方便起见,可以使用运算符访问公共集合,例如数组,列表,稀疏列表和映射。

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List<String>"/>
    <variable name="sparse" type="SparseArray<String>"/>
    <variable name="map" type="Map<String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

七、事件处理

数据绑定允许您编写从视图调度的表达式处理事件(例如,onClick()方法)。事件属性名称由监听器方法的名称确定,但有一些例外。例如,View.OnClickListener有一个方法onClick(),所以这个事件的属性是android:onClick

对于click事件,有一些专门的事件处理程序需要除android:onClick避免冲突之外的属性。您可以使用以下属性来避免这些类型的冲突:

监听器设置属性
SearchViewsetOnSearchClickListener(View.OnClickListener)android:onSearchClick
ZoomControlssetOnZoomInClickListener(View.OnClickListener)android:onZoomIn
ZoomControlssetOnZoomOutClickListener(View.OnClickListener)android:onZoomOut

您可以使用以下机制来处理事件:

7.1 方法引用
public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

绑定表达式可以将视图的单击监听器分配给 onClickFriend()方法,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.MyHandlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:onClick="@{handlers::onClickFriend}"/>
   </LinearLayout>
</layout>
7.2 监听器绑定
public class Presenter {
    public void onSaveClick(Task task){}
}

然后,您可以将click事件绑定到onSaveClick()方法,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="task" type="com.android.example.Task" />
        <variable name="presenter" type="com.android.example.Presenter" />
    </data>
    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:onClick="@{() -> presenter.onSaveClick(task)}" />
    </LinearLayout>
</layout>

八、关键字 Imports, variables, and includes

官方解释,简单易懂

The Data Binding Library provides features such as imports, variables, and includes. Imports make easy to reference classes inside your layout files. Variables allow you to describe a property that can be used in binding expressions. Includes let you reuse complex layouts across your app.

  • import
<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>//命名冲突时输入别名

导入View该类允许您从绑定表达式中引用它。以下示例显示如何引用 类的常量VISIBLEGONE常量View

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
  • variable
<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user" type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note" type="String"/>
</data>

生成的绑定类对于每个描述的变量都有一个setter和getter。

  • include

变量可以从包含的布局传递到包含的布局绑定中

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

九、可观察的对象

可观察性是指对象通知其他人数据变化的能力。数据绑定库允许您使对象,字段或集合可观察。

private static class User extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return this.firstName;
    }

    @Bindable
    public String getLastName() {
        return this.lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

我们使用 notifyPropertyChanged 来进行数据改变完成通知,但我们怎么通知一个数据即将改变?我们不得不写一个 @Bindable 注解在 getFirstName。这将会自动产生一个 BR.firstName,这个 BR 很像我们经常使用的 R 类文件,我们通过这些注解会自动生成它。

------ 本文结束 ------
坚持原创技术分享,您的支持将鼓励我继续创作!