Android DataBinding框架的基本使用

Demo地址

怎么配置DataBinding

在Module的gradle 文件下,AndroidStudio版本不通开启的方式也不同
AndroidStudio 3.x 版本

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

AndroidStudio 4.x 版本(也可以使用3.0的方式开启,但是4.0推荐使用下面的方法)

android {
   ...  
   buildFeatures{
       dataBinding = true
   }
}

这里有一个坑,就是如果子Module配置了DataBinding,必须在主Module也配置

怎么让一个 View 可以绑定数据



    

    

    

    

比原来的layout文件多了layout标签和data标签,这样格式的xml布局文件就是一个支持DataBinding的布局文件,可以通过快捷键Alt+Enter键来快速生成

DataBinding 中的被观察者 BaseObservable

如果想要你的UI随着数据的更新而更新,还需要实现BaseObservable

BaseObservable 是一个被观察者,UI组件会观察BaseObservable,如果数据发生了变化,则UI会更新。这里可以把BaseObservable 理解为数据的包装类。

看一个简单的实现

public class UserEntity extends BaseObservable {
    @Bindable
    private String nickname;
    @Bindable
    private String headUrl;

    public UserEntity(String nickname, String headUrl) {
        this.nickname = nickname;
        this.headUrl = headUrl;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
        notifyPropertyChanged(BR.nickname);
    }

    public String getHeadUrl() {
        return headUrl;
    }

    public void setHeadUrl(String headUrl) {
        this.headUrl = headUrl;
        notifyPropertyChanged(BR.headUrl);
    }
}

首先数据类实现BaseObservable,然后对需要被观察的数据用@Bindable注解
重写set/get 方法,然后在set 方法(数据更新的地方)调用notifyPropertyChanged(BR.id),UI就会被通知刷新UI

BR.id是DataBinding生成的id,用来区分数据的id,如果BR下面没有你的id,先检查一个有没有注解,然后再Rebuild 一下

单向绑定




    
        
    

    

        

        
    

单向绑定的话比较简单,通过@{}的方式就可以把数据绑定到UI上了
这里写了两个绑定,一个是"",一个是'',如果有做字符串操作的(比如例子中的拼接字符串),是不能使用""进行绑定的

双向绑定

双向绑定相对于单向绑定的语法上来说,只多了一个=


双向绑定在使用的过程中要注意到一点,就是绑定的这个属性,是否支持双向绑定,如果不支持,编译肯定是不会通过的。

下面是谷歌实现的双向绑定

  • AbsListView
    1. android:selectedItemPosition
  • CalendarView
    1. android:date
  • CompoundButton
    1. android:checked
  • DatePicker
    1. android:year
    2. android:month
    3. android:day
  • NumberPicker
    1. android:value
  • RadioGroup
    1.android:checkedButton
  • RatingBar
    1. android:rating
  • SeekBar
    1. android:progress
  • TabHost
    1. android:currentTab
  • TextView
    1. android:text
  • TimePicker
    1. android:hour
    2. android:minute

那么如果说系统提供的绑定方法不能够实现现有的需求怎么办?这里就需要到下面的自定义绑定方法了

自定义绑定 - 单向绑定

自定义单向绑定比较简单。只需要一个注解,一个方法就可以了
这里写一个用Glide加载网图,并且设置占位图的绑定方法

@BindingAdapter(value = {"bindUrl", "bindPlaceholder"}, requireAll = false)
public static void bindUrlAndPlaceholder(ImageView view, String url, int placeholder) {
    Glide.with(view).load(url).apply(new RequestOptions().placeholder(placeholder)).into(view);
}



    
        

    
    

    

        

    

@BindingAdapter这个注解是用来说明,我这个方法是一个绑定方法注解里需要两个参数valuerequireAll
value的类型是一个数组,数组的长度为方法参数长度-1(去掉View参数),然后顺序一一对应,bindUrlurl对应,bindPlaceholderplaceholder对应,view即被绑定的View
requireAll这个参数默认为true,它的意思是,value里面的数据是否全部都要绑定

自定义绑定 - 双向绑定

单向绑定可以只是set方法,双向绑定需要做的是,当被观察的View属性发生变化的时候,需要把自身的值给更新。用SwipeRefreshLayout举一个栗子

    @BindingAdapter("bindIsRefreshing")
    public static void setRefreshing(SwipeRefreshLayout refreshLayout, boolean isRefreshing) {
        if (refreshLayout.isRefreshing() != isRefreshing) {
            refreshLayout.setRefreshing(isRefreshing);
        }
    }

    @InverseBindingAdapter(attribute = "bindIsRefreshing", event = "onRefreshChange")
    public static boolean isRefreshing(SwipeRefreshLayout refreshLayout) {
        return refreshLayout.isRefreshing();
    }

    @BindingAdapter("onRefreshChange")
    public static void setOnRefreshListener(SwipeRefreshLayout refreshLayout, InverseBindingListener inverseBindingListener) {
        refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                inverseBindingListener.onChange();
            }
        });
    }

setRefreshing这个方法和 单向绑定一样,不需要多解释。
isRefreshingsetOnRefreshListener 这两个方法需要对照着看,
先看isRefreshing这个方法,返回了SwipeRefreshLayout.isRefreshing(),然后看上面的@InverseBindingAdapter注解,有两个参数,attribute表示被绑定的属性,我们上面因为是定义的bindIsRefreshing,所以这里和上面一样bindIsRefreshing

event这个参数,可以理解为isRefreshing的调用时机。这里转到底三个方法setOnRefreshListener,这个方法中的InverseBindingListener是一个DataBinding的接口,需要在属性发生变化时回调onChange方法,这样双向绑定的观察者就会知道属性发生了变化,就会更新自身的属性值

当栗子上的SwipeRefreshLayout触发OnRefreshListener.onRefresh时,会回调到InverseBindingListener.onChange方法,然后观察者收到回调后,就会调用isRefreshing方法来更新属性

需要注意的是,双向绑定中的set方法一定要加属性值得判断,就是当属性相同时,不调用View的set方法,避免触发死循环

你可能感兴趣的:(Android DataBinding框架的基本使用)