android中data binding的使用

来源:互联网 发布:linux diff命令的功能 编辑:程序博客网 时间:2024/06/05 17:22

Android Data Binding介绍

Data Binding是一个MVVM的架构框架,使用Data Binding对于我们开发应用有下面好处:

  • 可以直接在layout布局中的xml中绑定数据
  • 分离视图与业务逻辑
  • 适用于android 2.1以上的版本

搭建Data Binding环境

使用Data Binding需要下面条件:

  • gradle1.3 以上
  • android studio1.3以上(当然现在都到了2.2了^_^)

在项目的根目录下build.gradle添加dependenncy
这里写图片描述

为用到 Data Binding 的模块添加插件,修改对应的 build.gradle
这里写图片描述
需要注意的是,如果studio在2.0版本之后,可以直接在android中添加

dataBinding{        enabled = true    }

Data Binding入门

下面我通过一个简单的栗子,来实现业务和逻辑分离,并在不居中直接绑定数据。

新建一个java bean类

public class UserInfo {    public String name;    public String phone;}

添加layout布局

在layout中绑定数据,我们需要在原本的layout的跟布局中使用layout,并制定其和那个类相关。
这里写图片描述

另外我们也可以通过import来引入我们的user类对象
这里写图片描述

注意:java.lang.* 包中的类会被自动导入,可以直接使用

使用DataBindingUtil绑定布局

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);//        setContentView(R.layout.activity_main);        // 通过DataBindingUtil重新设置布局        ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);        // 创建一个UserInfo,并绑定数据        UserInfo userInfo = new UserInfo();        userInfo.name = "haha";        userInfo.phone = "1234567890";        // setUser方法是根据在xml中通过variable配置的user自动生成的        binding.setUser(userInfo);    }

可以看到,系统自动为我们的activity_main布局生成了对应的ActivityMainBinding类,我们也可以自己定义该Binding类的类名

<data class="TestLayoutMain">        <import type="com.example.myapplication.UserInfo" alias="AliasUserInfo"/>        <variable            name="user"            type="AliasUserInfo"/></data>

此时生成的Binding类名获取方式如下:

TestLayoutMain binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

布局中引用user类

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

另外,我们也可以使用jdk中提供的数据类型来进行设置,比如:

<variable    name="sex"    type="String"></variable>

为UserInfo对象添加sex属性

public String sex;

在布局中使用该属性

<TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@{sex}"        />

通过引用布局绑定数据

另外我们可以通过include标签来引用我们的指定的布局,并且传入user对象。

创建布局

user_layout.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android">    <data>        <variable            name="user"            type="com.example.myapplication.UserInfo"/>    </data>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content">            <TextView                android:layout_width="match_parent"                 android:layout_height="match_parent"                android:text="@{user.phone}"                />    </LinearLayout></layout>

在主布局中引用该布局

接下来,我们需要在主布局中通过include标签,引用到该布局,并且传递我们的user对象。

<include layout="@layout/user_layout"        bind:user="@{user}"        />

使用类方法

我们也可以在布局中直接使用定义好的类里面的方法

public class DataUtils {    public static String changeCharacter(String originalStr) {        if (null != originalStr) {            return originalStr.toUpperCase();        }        return null;    }}

在布局中引入当前类

<data>        <import type="com.example.myapplication.UserInfo"/>        <import type="com.example.myapplication.DataUtils"/>        <variable            name="user"            type="UserInfo"/>    </data>

直接调用该类的静态方法:

<TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@{DataUtils.changeCharacter(user.name)}"         />

类型别名

如果我们在布局中导入了两个不同包下的UserInfo对象,此时我们到底该使用哪一个呢。其实我们可以通过alias别名来进行设置。
这里写图片描述

三元运算符

<TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:textColor="#ff0000"        android:text="@{user.name ?? user.phone}"        />

上面@{user.name ?? user.phone}等价于:
user.name != null ? user.name : user.phone

android:visibility="@{user.mIshow ? View.VISIBLE : View.GONE}"

使用资源数据

这里,我们新创建两个颜色资源:

<color name="red">#ff0000</color><color name="blue">#0000ff</color>

在布局中使用:
这里写图片描述

 <plurals name="numberOfSongsAvailable">        <item quantity="one">One song found.</item>        <item quantity="other">%d songs found.</item> </plurals>

在布局中使用:
这里写图片描述

类型转换器

DataBinding也为我们提供了一个类型转换器,当xml中的类型,和需要显示的类型不同的时候,我们只需要在对应的实体类中添加一个@BindingConversion注解即可。

public class UserInfo {    public String name;    public String phone;    public boolean mIshow;    public String sex;    @BindingConversion    public static int convertToString(int color) {        switch (color) {            case Color.RED:                return R.string.red;            case Color.BLUE:                return R.string.blue;        }        return R.string.app_name;    }}

这里写图片描述
可以看到,上面我们在text中返回的是int类型,所以这里通过BindingConversion注解进行类型转换。

<variable            name="time"            type="java.util.Date"/><TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{time}"        />@BindingConversionpublic static String convertDate(Date date) {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        return sdf.format(date);}

NullPointException的检测

在DataBinding中,会自动为我们避免出现空指针,比如:user.name和user.age,如果user是null,那么user.name会返回null,user.age是int类型,所以默认返回0

集合类型数据的引用

常用的集合:arrays、lists、sparse lists以及maps,为了简便都可以使用[]来访问

  • 在UserInfo中增加一个Map集合
 public Map<String,Object> map = new ArrayMap<>(3);//添加设置数据userInfo.map.put("hello",111);userInfo.map.put("world","世界");
  • 在布局中使用
<TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text='@{String.valueOf((Integer)user.map["hello"])}'        /><TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text='@{user.map["world"]}' />

带Id的View

当我们在布局中为某一个控件增加id时候,DataBinding会自动生成该根据该id自动生成对应的实例,看下面栗子:

<TextView        android:id="@+id/dataBindId"        android:layout_width="match_parent"        android:layout_height="wrap_content"        />TestLayoutMain binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);        binding.dataBindId.setText("hello world");

ViewStub支持

<ViewStub        android:id="@+id/my_viewstub"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout="@layout/user_layout"        />TestLayoutMain binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);binding.myViewstub.inflate();

ViewStub的使用

 <ViewStub        android:id="@+id/my_viewstub"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout="@layout/stub_layout"        />// 注意这里AS可能会标红,可能是支持不好,但是不影响编译和运行binding.myViewstub.getViewStub().inflate();

事件绑定

同时我们可以通过DataBinding来绑定事件到指定的View,看下面的栗子:

<variable            name="clickListener"            type="android.view.View.OnClickListener" /> <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{user.name}"        android:onClick="@{clickListener}"        />

我们知道,当在xml布局文件中定义的每一个variable对象,系统都会生成其对应的setXXX方法。

TestLayoutMain binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);binding.setClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(v.getContext(), "setClickListener bind click ok", Toast.LENGTH_LONG).show();            }        });

监听数据变化

我们知道,很多时候我们的界面是需要实时改变数据的,当然DataBinding也为我们封装好了,看下面的栗子。

  • 创建POJO实例
public class UserInfo extends BaseObservable{    public String name;    public UserInfo(String name) {        this.name = name;    }    @Bindable    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;        notifyPropertyChanged(BR.name);    }}

这里我们需要动态改变name属性
1. 实体类继承自BaseObservable类
2. 为需要动态改变的属性增加get和set方法
3. 在get方法添加@Bindable注解
4. 在set方法中调用notifyPropertyChanged(BR.xx);来通知数据变化,其中xx为需要改变的属性

  • 在布局中引用该实体类
<import type="com.detail.pojo.UserInfo" alias="ObserUser"/><variable     name="obserUser"     type="ObserUser"/><TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{obserUser.name}"        />
  • 在代码中动态改变属性内容
final com.detail.pojo.UserInfo user = new com.detail.pojo.UserInfo("hello");        binding.setClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                user.setName("world");            }        });        binding.setObserUser(user);

使用ObservableField监听数据变化

前面我们创建的实体类,需要为属性设置get和set方法并且需要在set方法中通过notifyPropertyChanged来通知数据变化。这样多少有些麻烦,好在系统为我们提供了一系列的ObservableField,如下:
ObservableField,ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,
ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable

通过这些封装ObservableField就无需提供get和set方法了。看下面栗子:

  • 创建POJO实体类
public class UserInfo extends BaseObservable{    /**     * ObservableField,ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,     * ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable     */    public ObservableField<String> name = new ObservableField<>();    public ObservableInt age = new ObservableInt();    public ObservableBoolean isShow = new ObservableBoolean();}
  • 创建布局,通过variable标签引用该POJO
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android">    <data class="CustomeLayout">        <variable            name="user"            type="com.detail.pojo.UserInfo"/>        <variable            name="onClickListener"            type="android.view.View.OnClickListener"/>    </data><LinearLayout    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    >    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@{user.name}"         />    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@{user.age}"        />    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text='@{user.isShow ? "show" : "donotshow"}'        />    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@{user.name}"        android:onClick="@{onClickListener}"        /></LinearLayout></layout>
  • 在代码中动态改变属性
 protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        CustomeLayout binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.custom_main);        final com.detail.pojo.UserInfo user = new UserInfo();        user.age.set(22);        user.name.set("hello world");        user.isShow.set(true);        binding.setUser(user);        binding.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.d(TAG,"age is :"+user.age.get()+"  name is :"+user.name.get()+"   isShow is :"+user.isShow.get());                user.age.set(33);                user.name.set("yes it changed");                user.isShow.set(false);            }        });    }

看到了吧,其实同样很简单,google工程师已经为我们封装的很完美了。

参考:
Android官方数据绑定框架DataBinding(一)

Android官方数据绑定框架DataBinding(二)

Android官方数据绑定框架DataBinding(三)

0 0
原创粉丝点击