如何使用Data Binding(进阶篇)

一、notifyPropertyChanged方式更新指定数据

首先,来简单介绍下Observable:

  • Observable 基于观察者模式更新;

  • 它的出现,便是为了解决当我们的实体发生改变时,UI即时刷新。

先来一个小例子:

  • 假设我们现在有一个User对象,当修改其中一个属性,使其引用的部分更新为修改后的值。

那么针对这个需求,我们使用Observable即可分分钟搞定。这里,大家可以简单理解为,这个就是负责数据更新~

下面来个Demo试试:

Step 1: 实体类继承BaseObservable

package com.hlq.databindingdemo.bean;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import com.hlq.databindingdemo.BR;

public class ClassBean extends BaseObservable {
   private String classNo;
   private String classNum;
   private String className;
   public ClassBean(String className) {
       this.className = className;
   }
   public ClassBean(String className, String classNum) {
       this.className = className;
       this.classNum = classNum;
   }
   public ClassBean(String classNo, String classNum, String className) {
       this.classNo = classNo;
       this.classNum = classNum;
       this.className = className;
   }
   @Bindable
   public String getClassNo() {
       return classNo;
   }
   public void setClassNo(String classNo) {
       this.classNo = classNo;
   }
   @Bindable
   public String getClassName() {
       return className;
   }
   public void setClassName(String className) {
       this.className = className;
   }
   @Bindable
   public String getClassNum() {
       return classNum;
   }
   public void setClassNum(String classNum) {
       this.classNum = classNum;
   }
}

Step 2: 为字段设置notifyPropertyChanged

这里,老铁需要谨记一点即可:

想让谁更新,就给谁设置notifyPropertyChanged(BR.字段名)。

而设置的规则,简单如下:

例如,想为ClassBean中classNo设置更新,那么只需要在setClassNo中添加notifyPropertyChanged(BR.classNo);即可,其他同理。

那么,本小节演示所有字段设置更新,那么对应的代码段如下:

    public void setClassNo(String classNo) {
       this.classNo = classNo;
       notifyPropertyChanged(BR.classNo);
   }
   public void setClassName(String className) {
       this.className = className;
       notifyPropertyChanged(BR.className);
   }
   public void setClassNum(String classNum) {
       this.classNum = classNum;
       notifyPropertyChanged(BR.classNum);
   }

而为了突出演示效果,这里添加一个EditText,用于在用户输入数据时,动态修改实体,从而进行UI即时刷新。

同样,也需要初始化以及设置事件,下面一起看看:

    private ActivityObservableBinding mBinding;
   private ClassBean mClassBean = new ClassBean("001", "100", "A1T105");
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       mBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable);
       mBinding.setClassX(mClassBean);
       mBinding.setPresenter(new Presenter());
   }
   public class Presenter {
       public void onTextChanged(CharSequence s, int start, int before, int count) {
           mClassBean.setClassNo("No:" + s);
           mClassBean.setClassNum("Num:" + s);
           mClassBean.setClassName("Name:" + s);
       }
   }

xml当中也只是简单的调用事件以及赋值,简单贴出部分代码:

<EditText
   style="@style/titleStyle"
   android:onTextChanged="@{presenter.onTextChanged}" />
<TextView
   style="@style/contentStyle"
   android:text="展示数据更新-notifyPropertyChanged" />
<TextView
   style="@style/titleStyle"
   android:text="@{classX.classNo}" />
<TextView
   style="@style/titleStyle"
   android:text="@{classX.classNum}" />
<TextView
   style="@style/titleStyle"
   android:text="@{classX.className}" />

先来看一波效果:


有的小伙伴说了,这太麻烦了,我实体类属性字段有很多肿么办?一个个添加吗?

当然不。

二、notifyChange方式更新全部数据

基于上节,本次单独定义一个实体类,用于展示更新全部数据。

package com.hlq.databindingdemo.bean;
import android.databinding.BaseObservable;
import android.databinding.ObservableBoolean;
/**
* desc   : notifyChange 更新所有数据
* version: 1.0
*/

public class LoveBean extends BaseObservable {
   private String youSelf;
   private String mySelf;
   private ObservableBoolean isTrueLove = new ObservableBoolean();
   public LoveBean(String youSelf, String mySelf, boolean trueLove) {
       this.youSelf = youSelf;
       this.mySelf = mySelf;
       isTrueLove.set(trueLove);
   }
   public String getYouSelf() {
       return youSelf;
   }
   public void setYouSelf(String youSelf) {
       this.youSelf = youSelf;
   }
   public String getMySelf() {
       return mySelf;
   }
   public void setMySelf(String mySelf) {
       this.mySelf = mySelf;
   }
   public ObservableBoolean getIsTrueLove() {
       return isTrueLove;
   }
   public void setIsTrueLove(boolean isTrueLove) {
       this.isTrueLove.set(isTrueLove);
       notifyChange();
   }
}

这里需要注意,只需要为一个单独属性字段设置notifyChange即可实现所有数据均实现更新。

下面开始对应的初始化:

    private LoveBean mLoveBean = new LoveBean("Who are you", "H.L.Q.", true);
   ...
   mBinding.setLove(mLoveBean);
   ...
   mLoveBean.setYouSelf("Who are you?" + s);
   mLoveBean.setMySelf("H.L.Q." + s);
   mLoveBean.setIsTrueLove(!mLoveBean.getIsTrueLove().get());

一起来看看效果:


俩者区别在于:

  • 如果仅仅是想更新部分属性字段,只需要在要更新的属性字段set方法下添加notifyPropertyChanged(BR.属性字段名);

  • 如果是仅仅想更新全部属性字段,则随便在某个set的方法下添加notifyChange()。

当然,Data Binding的神奇之处还有很多,比如,它为我们提供了对应的一系列ObservableField,那么,下面,让我们一起去看看吧~

三、ObservableField Study
  • 有的小伙伴说了,忒麻烦,忒麻烦,我连get/set都不想搞,怎么破?

  • So easy~ 那都不叫事儿~

简单说一下ObservableField是什么:

  • 首先,ObservableField是归属于Observable旗下,作用就是为了简化操作,避免你写多余的get/set,当然喽,优点并不止这些;

  • 其次,Observable旗下包含了很多类似ObservableField的家伙,例如:ObservableInt、ObservableBoolean等。

  • 如何使用呢?你怎么使用String、int等,就怎么使用这个。说白了,就是一个配套的家伙。

那么接下来,简单搞俩个Demo熟悉下使用:

Example One:先来个ObservableField练练手

Step 1: 定义实体类

import android.databinding.ObservableField;

public class MissBean {
   public final ObservableField<String> missWho = new ObservableField<>();
   public final ObservableField<String> missYou = new ObservableField<>();
}

Step 2: 布局引用

引入命名空间。

<data>
   <variable
       name="missBean"
       type="com.hlq.databindingdemo.bean.MissBean" />

</data>

设置对应值。

<TextView
   style="@style/titleStyle"
   android:text="@{missBean.missWho}" />
<TextView
   style="@style/titleStyle"
   android:text="@{missBean.missYou}" />

Step 3: Activity中初始化 - 赋值

mMissBean = new MissBean();
mMissBean.missWho.set("在思念谁?");
mMissBean.missYou.set("在思念你~");
mBinding.setMissBean(mMissBean);

Step 4: 查看效果


有的小伙伴说了,那我如果想取值呢?怎么弄?

一张图包教包会!


Example Two:再来个稍稍复杂的玩玩

Step 1: 定义我们实体类

package com.hlq.databindingdemo.bean;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableField;
import android.databinding.ObservableInt;
/**
* desc   : Observable Field 实体类
*/

public class ObservableFieldBean {
   public ObservableField<String> filedName = new ObservableField<>();
   public ObservableInt fileAge = new ObservableInt();
   public ObservableBoolean fileStore = new ObservableBoolean();
}

可以看到,我们这次不仅仅使用了ObservableField,还有ObservableInt以及ObservableBoolean,用法是不是很Easy?

Step 2: 引入命名空间,赋值

<data>
   <variable
       name="filedBean"
       type="com.hlq.databindingdemo.bean.ObservableFieldBean" />

</data>

接下来赋值:

<TextView
   style="@style/contentStyle"
   android:text="Observable Field" />
<TextView
   style="@style/titleStyle"
   android:text="@{filedBean.filedName}" />
<TextView
   style="@style/titleStyle"
   android:text='@{"年纪:"+filedBean.fileAge}' />
<TextView
   style="@style/titleStyle"
   android:text='@{"结果为:"+filedBean.fileStore}' />

Step 3: 初始化

mFiledBean = new ObservableFieldBean();
mFiledBean.filedName.set("贺大大");
mFiledBean.fileAge.set(22);
mFiledBean.fileStore.set(true);
mFieldBinding.setFiledBean(mFiledBean);

Step 4: 查看演示效果


四、ObservableArrayList Study

Step 1: 引入命名空间,声明类型

<data>
   <import type="android.databinding.ObservableArrayList" />
   <variable
       name="loveList"
       type="ObservableArrayList&lt;String>" />

</data>

这里需要注意,指定type时,ObservableArrayList类型里面不能包含<,而是通过 < ; 代替

Step 2: 赋值

<TextView
   style="@style/contentStyle"
   android:text="ObservableArrayList Study" />
<TextView
   style="@style/titleStyle"
   android:text="@{loveList.get(0)}" />
<TextView
   style="@style/titleStyle"
   android:text="@{loveList.get(1)}" />

是不是很Easy,直接通过下标去访问即可。

Step 3: 查看演示效果


五、ObservableMap Study

Step 1: 布局添加引用

<data>
   <import type="android.databinding.ObservableMap" />
   <variable
       name="loveMap"
       type="ObservableMap&lt;String,String>" />

</data>

Step 2: 赋值

<TextView
   style="@style/contentStyle"
   android:text="ObservableArrayMap Study" />

<TextView
   style="@style/titleStyle"
   android:text='@{loveMap["name"]}' />

<TextView
   style="@style/titleStyle"
   android:text='@{loveMap["age"]}' />

Step 3:  初始化

ObservableMap<String, String> testMap = new ObservableArrayMap<>();
testMap.put("name", "贺大宝,心情不美丽");
testMap.put("age", "22的年龄,啧啧");
mFieldBinding.setLoveMap(testMap);

Step 4:  查看效果演示图


六、RecyclerView与DataBinding使用

目前的RecyclerView可谓火爆了半边天,试问,现在还是谁没用过?

先撸一波效果图~


首先,我们来回顾下,之前我们最普通关于RecyclerView的使用:

  1. 定义布局文件,放置RecyclerView;

  2. 定义对应的item文件;

  3. 编写对应的Java Bean以及Adapter,其中Adapter中需要单独编写ViewHolder类,且此类需继承RecyclerView.ViewHolder。

大概简单来讲就是以上三个步骤,那么我们根据以上三步骤并结合当前Data Binding去一步步学习掌握如何二者结合使用。

Step 1: 定义布局文件

这里需要注意以下几点:

  • 引入所需Java Bean以及我们的ObservableArrayList;

  • 通过app:data属性将我们的List传递到RecyclerView中。(注意使用app:data需要导入命名空间,并且RecyclerView本身并不提供setData的api,所以我们只能造一个。

上面说到,由于RecyclerView本身并不提供setData方式,所以我们需要自己造一个,那么有的小伙伴就会问了,我之前没使用Data Binding的时候,也不需要setData呀。其实这个东西大家可以简单理解为,它就是一个桥接的作用,将传递过来的数据与RecyclerView绑定,也就是真正让RecyclerView拿到传递的数据。 

定义桥接类如下:

package com.hlq.databindingdemo.util;
import android.databinding.BindingAdapter;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.hlq.databindingdemo.adapter.ShowLoveHistoryAdapter;
import com.hlq.databindingdemo.bean.LoveBean;
import java.util.List;
/**
* desc   : 桥接ReccyclerView与Data Binding
* version: 1.0
*/

public class BindUtils {
   @BindingAdapter("data")
   public static void setShowLoveHistoryData(RecyclerView recyclerView,
                                             List<LoveBean> loveList)
{
       recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
       recyclerView.setAdapter(new ShowLoveHistoryAdapter(recyclerView.getContext(), loveList));
   }
}

而我们放置RecyclerView布局如下:

<?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>
       <import type="com.hlq.databindingdemo.bean.LoveBean" />
       <import type="android.databinding.ObservableArrayList" />
       <variable
           name="loveList"
           type="ObservableArrayList&lt;LoveBean>" />

   </data>
   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:context="com.hlq.databindingdemo.activity.RecyclerViewActivity">

       <android.support.v7.widget.RecyclerView
           android:id="@+id/showLove"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           app:data="@{loveList}" />

   </LinearLayout>
</layout>

Step 2: 定义对应的item文件

这里我们简单思考下:

既然是Adapter形式,那么传递到Item中当然是一个实体类形式,我们只需要将每次遍历得到的实体依次赋给item所需内容即可。

如演示图所示,这里为了方便就不单独定义实体类了,直接使用原有的,如下:

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

   <data>
       <variable
           name="love"
           type="com.hlq.databindingdemo.bean.LoveBean" />

   </data>
   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <ImageView
           android:id="@+id/icon"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_margin="15dp"
           android:background="@drawable/ic_launcher_round" />

       <TextView
           style="@style/contentStyle"
           android:layout_centerVertical="true"
           android:layout_marginTop="15dp"
           android:layout_toRightOf="@id/icon"
           android:text="@{love.youSelf}"
           tools:text="姓名" />

       <View
           android:layout_width="match_parent"
           android:layout_height="1dp"
           android:layout_below="@id/icon"
           android:background="#fff" />

   </RelativeLayout>
</layout>

item效果如下:


Step 3: 编写Adapter

package com.hlq.databindingdemo.adapter;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.hlq.databindingdemo.R;
import com.hlq.databindingdemo.bean.LoveBean;
import com.hlq.databindingdemo.databinding.ItemLoveHistoryShowBinding;
import com.hlq.databindingdemo.holder.ShowLoveHistoryHolder;
import java.util.List;
/**
* desc   : RecyclerView与DataBinding使用
* version: 1.0
*/

public class ShowLoveHistoryAdapter extends RecyclerView.Adapter<ShowLoveHistoryHolder> {
   private Context mContext;
   private List<LoveBean> mLoveList;
   public ShowLoveHistoryAdapter(Context mContext, List<LoveBean> mLoveList) {
       this.mContext = mContext;
       this.mLoveList = mLoveList;
   }
   @Override
   public ShowLoveHistoryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       ItemLoveHistoryShowBinding binding = DataBindingUtil.inflate(
               LayoutInflater.from(mContext),
               R.layout.item_love_history_show,
               parent, false);
       return new ShowLoveHistoryHolder(binding);
   }
   @Override
   public void onBindViewHolder(ShowLoveHistoryHolder holder, int position) {
       holder.getBinding().setLove(mLoveList.get(position));
       // 立即刷新界面,防止列表更新不及时,导致数据错乱
       holder.getBinding().executePendingBindings();
   }
   @Override
   public int getItemCount() {
       return mLoveList == null ? 0 : mLoveList.size();
   }
}

这里为了方便,单独将ViewHolder抽取出来。

package com.hlq.databindingdemo.holder;
import android.support.v7.widget.RecyclerView;
import com.hlq.databindingdemo.databinding.ItemLoveHistoryShowBinding;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time   : 2018/02/24
* desc   : RecyclerView 所需Holder
* version: 1.0
*/

public class ShowLoveHistoryHolder extends RecyclerView.ViewHolder {
   private ItemLoveHistoryShowBinding binding;
   public ShowLoveHistoryHolder(ItemLoveHistoryShowBinding binding) {
       super(binding.getRoot());
       this.binding = binding;
   }
   public ItemLoveHistoryShowBinding getBinding() {
       return binding;
   }
   public void setBinding(ItemLoveHistoryShowBinding binding) {
       this.binding = binding;
   }
}

Step 4: 初始化

package com.hlq.databindingdemo.activity;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableArrayList;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.hlq.databindingdemo.R;
import com.hlq.databindingdemo.bean.LoveBean;
import com.hlq.databindingdemo.databinding.ActivityRecyclerViewBinding;
/**
* desc   : RecyclerView与DataBinding使用
* version: 1.0
*/

public class RecyclerViewActivity extends AppCompatActivity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       ActivityRecyclerViewBinding binding =
               DataBindingUtil.setContentView(this, R.layout.activity_recycler_view);
       ObservableArrayList<LoveBean> loveList = new ObservableArrayList<>();
       for (int i = 0; i < 30; i++) {
           loveList.add(new LoveBean("youSelf" + i, "mySelf" + i, true));
       }
       binding.setLoveList(loveList);
   }
}

嗯,小手一点,运行一波,走起~

七、老方式设置RecyclerView点击事件

来来来,Come on,我们一起回顾下当年如何简单有效实现RecyclerView并为其添加点击事件:

  • Activity中摆放好RecyclerView;

  • 初始化,编写item以及对于Adapter、ViewHolder;

  • 当然,不要忘记在adapter中设置事件,Activity中回调。

那么基于以上路子,我们一块快速简单有效的撸一波有关结合Data Binding的用法吧~

Step 1:摆放RecyclerView

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

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       tools:context=".activity.NormalRecyclerViewActivity">

       <TextView
           style="@style/contentStyle"
           android:text="换种姿势玩转RecyclerView" />

       <android.support.v7.widget.RecyclerView
           android:id="@+id/showList"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />

   </LinearLayout>
</layout>

Step 2:摆放Item_layout

这里需要注意,因为我们是结合Data Binding,而真正落实到Item时,仅仅是一个Model,也就是我们最终的实体类。
So,在此,我们需要将我们的Model传递进去。

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

   <data>
       <variable
           name="user"
           type="com.hlq.databindingdemo.bean.UserBean" />

   </data>
   <LinearLayout
       android:id="@+id/parent_list"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">

       <TextView
           android:id="@+id/item_list"
           style="@style/contentStyle"
           android:text="@{user.userName}"
           tools:text="item测试数据" />

       <View
           android:layout_width="match_parent"
           android:layout_height="2dp"
           android:background="#fff" />

   </LinearLayout>
</layout>

Step 3:编写Adapter

这里简单总结下,看看我们的Adapter中需要落实些什么鬼~!

  • 继承RecyclerView.Adapter,实现方法添加ViewHolder并继承RecyclerView.ViewHolder,而我们这次的Holder只需要Binding即可;

  • 传递Model,刷新RecyclerView;

  • 设置interface onItemClickListener;

嗯,基于以上三点,开始撸本次代码:

package com.hlq.databindingdemo.adapter;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hlq.databindingdemo.R;
import com.hlq.databindingdemo.bean.UserBean;
import com.hlq.databindingdemo.databinding.ItemShowListBinding;
import java.util.List;

public class ShowListAdapter extends RecyclerView.Adapter<ShowListAdapter.ViewHolder> {
   private Context mContext;
   private List<UserBean> mUserBeanList;
   private onItemClickListener mOnItemClickListener;
   private ItemShowListBinding mListBinding;
   public ShowListAdapter(Context context, List<UserBean> userBeanList) {
       this.mContext = context;
       this.mUserBeanList = userBeanList;
   }
   @Override
   public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       mListBinding = DataBindingUtil.inflate(LayoutInflater.from(mContext), R.layout.item_show_list, parent, false);
       return new ViewHolder(mListBinding);
   }
   @Override
   public void onBindViewHolder(ViewHolder holder, final int position) {
       // 传递Model
       holder.mListBinding.setUser(mUserBeanList.get(position));
       // 刷新RecyclerView
       holder.mListBinding.executePendingBindings();
       // 设置事件 只需要传递当前item所需Model(Java Bean)即可
       if (mOnItemClickListener != null) {
           holder.mListBinding.parentList.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   mOnItemClickListener.onItemClickListener(mUserBeanList.get(position));
               }
           });
       }
   }
   @Override
   public int getItemCount() {
       return mUserBeanList.size();
   }
   class ViewHolder extends RecyclerView.ViewHolder {
       private ItemShowListBinding mListBinding;
       public ViewHolder(ItemShowListBinding listBinding) {
           super(listBinding.getRoot());
           this.mListBinding = listBinding;
       }
   }
   public void setOnItemClickListener(onItemClickListener onItemClickListener) {
       this.mOnItemClickListener = onItemClickListener;
   }
   public interface onItemClickListener {
       void onItemClickListener(UserBean userBean);
   }
}

Step 4:初始化RecyclerView、数据以及设置事件处理

    private ActivityNormalRecyclerViewBinding mNormalBinding;
   private ShowListAdapter mShowListAdapter;
   private List<UserBean> mShowList;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       mNormalBinding = DataBindingUtil.setContentView(this, R.layout.activity_normal_recycler_view);
       initData();
       initRecyclerViewSetting();
   }
   private void initData() {
       mShowList = new ArrayList<>();
       for (int i = 0; i < 30; i++) {
           mShowList.add(new UserBean("贺大大" + i));
       }
   }
   private void initRecyclerViewSetting() {
       mNormalBinding.showList.setLayoutManager(new LinearLayoutManager(this));
       mShowListAdapter = new ShowListAdapter(this, mShowList);
       mShowListAdapter.setOnItemClickListener(new ShowListAdapter.onItemClickListener() {
           @Override
           public void onItemClickListener(UserBean userBean) {
               Toast.makeText(NormalRecyclerViewActivity.this, "点击了:" + userBean.getUserName(), Toast.LENGTH_SHORT).show();
           }
       });
       mNormalBinding.showList.setAdapter(mShowListAdapter);
   }

Step 5:运行一波,查看效果


嗯,简单的玩完了,下面基于第六小节实现RecyclerView点击~

八、设置RecyclerView点击事件

既然本小节基于第六小节实现item点击,那么多余的部分LZ这里不再叙述,这里着重讲几点思路:

  • 由于我们的Adapter被单独抽取到BindUtil中进行初始化,那么对应的,我们也得在BindUtil初始化Adapter为其设置事件并进行后续处理;

  • 而对应的Adapter则主要在Bind数据时,单独为Icon设置点击事件,其它暂时不需要改动。

当然为了便于接收者处理,这里我们的事件直接传递Model,Adapter关键代码如下:

    @Override
   public void onBindViewHolder(ShowLoveHistoryHolder holder, final int position) {
       holder.getBinding().setLove(mLoveList.get(position));
       // 立即刷新界面,防止列表更新不及时,导致数据错乱
       holder.getBinding().executePendingBindings();
       // 设置事件
       if (mOnItemClickListener != null) {
           holder.getBinding().icon.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   mOnItemClickListener.OnItemClickListener(mLoveList.get(position));
               }
           });
       }
   }
   public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
       this.mOnItemClickListener = onItemClickListener;
   }
   public interface OnItemClickListener {
       void OnItemClickListener(LoveBean loveBean);
   }

而对应的BindUtils中则只需要设置事件实例以及处理事件即可:

    @BindingAdapter("data")
   public static void setShowLoveHistoryData(final RecyclerView recyclerView,
                                             List<LoveBean> loveList)
{
       recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
       ShowLoveHistoryAdapter adapter = new ShowLoveHistoryAdapter(recyclerView.getContext(), loveList);
       adapter.setOnItemClickListener(new ShowLoveHistoryAdapter.OnItemClickListener() {
           @Override
           public void OnItemClickListener(LoveBean loveBean) {
               Toast.makeText(recyclerView.getContext(), "点击了:" + loveBean.getYouSelf(), Toast.LENGTH_SHORT).show();
           }
       });
       recyclerView.setAdapter(adapter);
   }

基于第六小节修改完毕,运行走一波~


九、当Data Binding遇到ImageView

在我们的上面有关RecyclerView时,大家注意到一个@BindingAdapter("data")么?

这个东西是什么?

简单可以理解为:

@BindingAdapter()类似一个桥梁,主要负责数据到Data Binding层,同样,牛掰的地方也在于,可以为你想使用的控件硬生生加个特异功能~

好比我们的RecyclerView原本没有接收数据的属性,但是,薇薇改动后,就这么神器的有了~~~

同理,依照上面如何为RecyclerView添加Data,下面先来撸一个有关ImageView的Util:

package com.hlq.databindingdemo.util;
import android.databinding.BindingAdapter;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import com.bumptech.glide.Glide;

public class ImageUtils {
   @BindingAdapter("imageResource")
   public static void setImageResource(
           ImageView imageView,
           int imgID)
{
       imageView.setImageResource(imgID);
   }
   @BindingAdapter("imageDrawable")
   public static void setImageDrawable(
           ImageView imageView,
           Drawable imgDrawable)
{
       imageView.setImageDrawable(imgDrawable);
   }
   @BindingAdapter({"defaultImg", "loadingImg", "errorImg"})
   public static void setImageForGlide(
           ImageView imageView,
           Drawable defaultImg,
           String imageAddress,
           Drawable errorImg)
{
       Glide.with(imageView.getContext())
               .load(imageAddress)
               .error(errorImg)
               .placeholder(defaultImg)
               .into(imageView);
   }
}

布局里面就很easy咯(不过这里要注意,调用者顺序以及类型需要统一,不然真的就GG了~)

<?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>
       <variable
           name="image"
           type="com.hlq.databindingdemo.bean.ImageBean" />

   </data>
   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:gravity="center"
       android:orientation="vertical"
       tools:context=".activity.ImageViewActivity">

       <ImageView
           android:layout_width="80dp"
           android:layout_height="80dp"
           app:imageResource="@{image.imageResID}" />

       <ImageView
           android:layout_width="80dp"
           android:layout_height="80dp"
           android:layout_marginTop="15dp"
           app:imageDrawable="@{@drawable/hlq_gzh}" />

       <ImageView
           android:layout_width="80dp"
           android:layout_height="80dp"
           android:layout_marginTop="15dp"
           app:defaultImg="@{@drawable/hlq_gzh}"
           app:errorImg="@{@drawable/ic_launcher_round}"
           app:loadingImg="@{image.imgUrl}" />

   </LinearLayout>
</layout>

而对应Activity中则很easy,初始化即可:

mImageBinding = DataBindingUtil.setContentView(this, R.layout.activity_image_view);
ImageBean imageBean = new ImageBean();
imageBean.imageResID = R.drawable.ic_launcher_round;
imageBean.imgUrl = "http://d.hiphotos.baidu.com/image/pic/item/6159252dd42a2834171827b357b5c9ea14cebfcf.jpg";
mImageBinding.setImage(imageBean);

查看效果:


十、十全十美,进阶收宫,来个注解完美告白

之前我们也多多少少使用了几个项目中常用的注解,而本文最后,拓展几个可能会用到的注解,来一个进阶篇完美谢幕~

先来俩个示例:

<?xml version="1.0" encoding="utf-8"?>
<layout>
   <data>
       <variable
           name="vv"
           type="com.hlq.databindingdemo.bean.VVBean" />

   </data>
   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       tools:context=".activity.WordActivity">

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="15dp"
           android:background="@{vv.vHeartBg ? @color/c_yellow : @color/c_while}"
           android:gravity="center"
           android:padding="15dp"
           android:text="VV内心颜色如同背景色"
           android:textColor="#000" />

       <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="15dp"
           android:background="@color/colorAccent"
           android:gravity="center"
           android:padding="15dp"
           android:text="@{vv.vDesc}"
           android:textColor="#000" />

   </LinearLayout>
</layout>

如下效果:


最后为大家提溜过来@BindingMethods以及@BindingMethod这俩个注解。

@BindingMethods以及@BindingMethod,这俩货是一对儿,你别想着拆散人俩,小心AS不放过你,那么具体他们使用以及场景又有哪儿些呢?

  • @BindingMethods,通常作为类的一个注解,它的作用,便是为其类或者实例添加新的技能;

  • @BindingMethod:苦逼执行者,旗下有三个小弟,如下:

  • type:给谁增加技能;

  • attribute :别人怎么激活这个技能;

  • method:这个技能被激活后会什么大招

首先,设置我们大招类:

package com.hlq.databindingdemo.weight;
import android.content.Context;
import android.databinding.BindingMethod;
import android.databinding.BindingMethods;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import android.widget.Toast;
/**
* desc   : 大招类 主动激活
* version: 1.0
*/

@BindingMethods(
       @BindingMethod(
               type = AppCompatTextView.class, // 目标
               attribute = "activation", // 激活方式
               method = "setActivation" // 激活后链接自动释放大招
       )
)
public class VVBiuView extends AppCompatTextView {
   public VVBiuView(Context context, @Nullable AttributeSet attrs) {
       super(context, attrs);
   }
   /**
    * 主动激活技能,将薇薇轰上天~
    *
    * @param msg
    */

   public void setActivation(String msg) {
       Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
   }
}

大招蓄势待发,下面开始布置环境(LZ这里顽皮一波):

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

   <data>
       <variable
           name="vv"
           type="com.hlq.databindingdemo.bean.VVBean" />

   </data>
   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       tools:context=".activity.WordActivity">

       <com.hlq.databindingdemo.weight.VVBiuView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="15dp"
           android:background="@color/colorPrimary"
           android:padding="15dp"
           android:text="我是隐藏大招~"
           app:activation="@{vv.vDesc}"/>

   </LinearLayout>
</layout>

实体类:

package com.hlq.databindingdemo.bean;

public class VVBean {
   public boolean vHeartBg;
   public String vDesc;
   public VVBean(boolean vHeartBg, String vDesc) {
       this.vHeartBg = vHeartBg;
       this.vDesc = vDesc;
   }
}

最后,简单实例化一下:

mWordBind = DataBindingUtil.setContentView(this, R.layout.activity_word);
mWordBind.setVv(new VVBean(true, "程序猿,Oh,程序媛一枚,灵活的双手编织动人的世界~"));

看下效果~


GitHub查看地址

https://github.com/HLQ-Struggle/DataBindingDemo


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值