Android DataBinding之初体验

1,710 阅读5分钟

(一)

关于DataBinding

Google推出DataBinding有一段时间,但是目前来看没有几个人用(尴尬),当然Google推出很多东西都没用户(哈哈),不过作为程序猿
学习这个东西还是很有必要的,毕竟技术的革新都是在一点点试错中发展壮大。此系列参考官方文档。
说明:
支持:Android 2.1 (API level 7+)
要求:Gradle插件至少1.5.0-alpha1或更高,Android Studio 1.3+

构建环境

使用之前要先从Support respository下载支持包,不过现在基本上都有的,没有support还怎么玩。
让后在app模块的build.gradle中添加如下:

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

注意:如果使用了library,而这个库使用了databinding,主模块也要配置。

布局文件

databinding的布局文件是区别于传统的layout文件,跟节点是以layout开头的,e.g.

    <?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>

data节点中定义变量名称,type是变量的类型(全名:包名+类名)。
而使用这个变量类似:

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

Data Object

上面已经写好了布局文件,已经定义了user变量,下面我们就定义一个User类,

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

这样写的实体通常是不会变化的,就跟我们平日写的JavaBean一样,但是字段必须是public和final的,还有另一种写法

    public class User {
        // private final 但是有getter
       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;
       }
    }

绑定数据

默认定义好了layout就会生成一个以“Binding”结尾同名的丙丁对象,让后通过DataBindingUtil来将layout和Activity绑定。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
       User user = new User("Test", "User");
       binding.setUser(user);
    }
  1. 将layout和Activity绑定
  2. 创建一个实体
  3. 将实体和布局关联起来

运行

上面简单几步,创建了一个DataBinding App现在运行起来,看看效果。

事件处理

上面只是一个简单的示例,毕竟没有人写一个只做展示而没有交互的应用,有交互必然有事件处理。DataBinding同样可以处理这些。

  1. 方法引用
  2. 监听绑定

    方法引用

  3. 定义一个类
     public class MyHandlers {
         public void onClickFriend(View view) { 
             Toast.makeText(view.getContext(), "Hello World", Toast.LENGTH_SHORT).show();
         }
     }
  4. 修改布局文件
     <?xml version="1.0" encoding="utf-8"?>
     <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable name="handlers" type="com.example.Handlers"/>
            <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>
    data节点申明变量,和类型
    andorid:onClick中调用函数,
  5. 赋值
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
         User user = new User("Test", "User");
         binding.setUser(user);
         binding.setHandlers(new MyHandlers()); // 给变量赋值
     }
    这样我们的时间就绑定好了,我们运行点击,就会弹出Toast。
    说明:如果没有赋值,不会报错,也不会弹出Toast,相当于没有绑定事件。

监听绑定

这种方式只有在Gradle插件version 2.0+上才能使用。

  1. 定义监听类
    Task表示回调参数
     public class Presenter {
         public void onSaveClick(Task task){}
     }
  2. 修改layout文件
       <?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>
    android:onClick="@{() -> presenter.onSaveClick(task)}" /> 使用lambda表达试,也可以使用下面方式
    android:onClick="@{(view) -> presenter.onSaveClick(task)}"
    两种方式各有特点,根据自己需要来选择。

(二)

上节我们讲了基本使用,这节我们继续讲讲已谢基本用法
说明:前期文章参考官方文档,因为基础知识官方写的很清楚。

导包

基本定义

上节我们使用了一下基础导包,定义一个变量,如:

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

这样写有个问题,当有多个同样类型的变量时候,就显得比较麻烦了,这里DataBinding库提供了另一中方式
可以先导包,然后在定义变量,

<data>
       <import type="android.view.View"/>
       <!--导入User-->
       <import type="com.lowett.databinding.User"/>

       <!--定义变量-->
       <variable
           name="user"
           type="User"
          />

       <variable
           name="listner"
           type="com.lowett.databinding.HandleClick"/>
   </data>

定义别名

如果类冲突,我们还可以定义别名。

<data>

       <import type="android.view.View"/>
       <!--导入User 并定义别名-->
       <import type="com.lowett.databinding.User" alias="MyUser"/>

       <!--定义变量-->
       <variable
           name="user"
           type="MyUser"
          />

       <variable
           name="listner"
           type="com.lowett.databinding.HandleClick"/>
   </data>

范型定义

在Java中我们可以定义范型,在layout同样可以,但是其中的括号需要特俗定义否则会报错。

<data>

      <import type="java.util.List"/>
      <import type="android.view.View"/>
      <!--导入User 并定义别名-->
      <import type="com.lowett.databinding.User" alias="MyUser"/>

      <!--定义变量-->
      <variable
          name="user"
          type="MyUser"
         />
      <!--定义范型, 如果显示红色没关系可以编译成功-->
      <variable
          name="users"
          type="List&lt;MyUser&gt;"/>

      <variable
          name="listner"
          type="com.lowett.databinding.HandleClick"/>
  </data>

静态方法

导入类型的时候我们也可导入工具类等的静态方法。

<data>
        <import type="com.lowett.databinding.utils.Utils"/>
</data>

使用:

<TextView
           android:layout_width="wrap_content"
           android:text="@{Utils.test()}"
           android:layout_height="wrap_content"/>

默认导入的变量

在layout中有默认导入几种常用的类型,比如String,Context等,这些何以直接使用,如果显式指定了类型将会修改掉默认的。
在layout中还有一个context变量可以直接使用。
如我们获取屏幕尺寸:
注意:需要讲int转换为String。
这里并没有定义context,以及导入String包,默认有。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <import type="com.lowett.databinding.utils.Utils"/>

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:text="@{String.valueOf(Utils.getScreenWidth(context))}"
            android:layout_height="wrap_content"/>

    </LinearLayout>
</layout>

Utils.java:

public class Utils {
    public  static String test() {
        return "Test";
    }

    public static int getScreenWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }
}

自定义类名

默认的我们生成的binding类名是以布局文件的名字接一个Binding为后缀,我们也可以修改这个名字。
如:

<data class="MyDataClass">

  </data>

在布局文件中data节点天街class属性并定义名字,生成MyDataClass绑定对象。位于跟包名下。
如果向指定包名,那么写全名即可。

<data class="com.lowett.databinding.utils.MyDataClass">

  </data>

这样将会在com.lowett.databinding.utils下面生成绑定类。

参考官方文档。
未完待续