1. 程式人生 > >Android DataBinding使用總結(三)列表展示

Android DataBinding使用總結(三)列表展示

前言

在我的前兩篇文章中,簡單學習了以下內容:

本文將進行闡述如何通過DataBinding展示RecyclerView列表

先看一下效果:

這裡寫圖片描述

1.每個item展示Student name 和Student age兩個Button

2.點選name時,觸發點選事件

3.點選age時,觸發點選事件,同時修改該控制元件的paddingLeft值

一、Activity程式碼

1.activity:先大概看一遍,不需要都看懂,我們後面會講

public class RecyclerBindActivity extends AppCompatActivity
{
private ActivityRecyclerBindBinding binding; private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bind(); } private void bind() { binding = DataBindingUtil.setContentView(this
, R.layout.activity_recycler_bind); ArrayList<Student> students = getStudents(); SimpleBindAdapter adapter = new SimpleBindAdapter(students, R.layout.item_recycler_view); adapter.setItemPresenter(new RecyclerBindPresenter()); binding.recyclerView .setLayoutManager(new
LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); binding.recyclerView .setAdapter(adapter); } //presenter控制點選事件 public class RecyclerBindPresenter implements IBaseBindingPresenter { public void onNameClick(Student student) { Toast.makeText(RecyclerBindActivity.this, student.name.get() + "要改名字", Toast.LENGTH_SHORT).show(); student.name.set("我改名字啦!"); } /** * 點選使用者年齡 += 3,且空間的左內邊距+=3; * {@link com.mei_husky.samplemvvm.view.bind.BindingUtil} */ public void onAgeClick(Student student) { Toast.makeText(RecyclerBindActivity.this, String.valueOf("漲了三歲"), Toast.LENGTH_SHORT).show(); student.setAge(student.getAge()+3); } } private ArrayList<Student> getStudents() { ArrayList<Student> students = new ArrayList<>(); students.add(new Student("jack", 12)); students.add(new Student("rose", 13)); students.add(new Student("qingmei2", 18)); students.add(new Student("unknown", 21)); return students; } }

2.layout程式碼:

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

    </data>

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

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

    </LinearLayout>
</layout>

二、奇怪的Adapter

我們來看看Adapter程式碼:

public class SimpleBindAdapter extends BaseBindingAdapter<Student, ItemRecyclerViewBinding> {

    public SimpleBindAdapter(List<Student> mDatas, int layoutId) {
        super(mDatas, layoutId);
    }

    /**
     * 如果有特殊需求可以實現在該方法中
     * @param holder
     */
    @Override
    public void onCreateViewHolder(BaseViewHolder<ItemRecyclerViewBinding> holder) {

    }
}

是不是很難理解!

Adapter怎麼長成這樣了?ViewHolder呢?

事實上這就是DataBinding Magic的地方,我們首先要知道ViewHolder的意義:用來處理資料和控制元件的互動,也就是說把資料放在控制元件上面,控制元件被點選之後我們再處理控制元件的點選事件,即:

資料 -> 控制元件
控制元件 -> 資料

而DataBinding能夠實現的就是資料和控制元件的資料繫結,所以我們只要略微做出處理,就能夠通過了了幾行程式碼實現列表!實際上,大部分的列表需求都不需要額外的Adapter和ViewHolder!

我們如何才能基本拋棄Adapter和ViewHolder實現列表呢,或者說我們需要什麼才能展示列表:

1、資料來源Datas

我們當然需要資料來源,這是我們需要去展示的,展示在item_layout上去

2、item的layoutId

我們知道了layoutId,就能通過DataBinding進行資料繫結。

3、UI排程器(Adapter和ViewHolder)

顯然我們並不是太需要他們了,待會我們會實現一個BaseAdapter和BaseViewHolder,從而一次建立,之後到處使用就可以啦

4、點選事件處理器Presenter

細心的讀者能發現,我們已經放在了Activity中的Presenter去處理所有的點選事件了,我們將點選事件的所有處理全部放在Presenter中,然後呼叫adapter.setItemPresenter()將響應事件傳入即可。

三、強擼一波程式碼

0.item_layout:

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

    <data>

        <variable
            name="itemPresenter"
            type="com.mei_husky.samplemvvm.view.activity.RecyclerBindActivity.RecyclerBindPresenter" />

        <variable
            name="data"
            type="com.mei_husky.samplemvvm.model.Student" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:background="#ff0"
        android:orientation="horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAllCaps="false"
            android:layout_margin="16dp"
            android:gravity="center_vertical"
            android:onClick="@{() -> itemPresenter.onNameClick(data)}"
            android:text="@{`Student Name : `+ data.name.get()}" />

        <!--顯示年齡,點選年齡+3,同時paddingleft也繫結年齡-->
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:textAllCaps="false"
            android:gravity="center_vertical"
            android:onClick="@{() -> itemPresenter.onAgeClick(data)}"
            android:paddingLeft="@{data.age}"
            android:text="@{`Student Age : `+data.age}" />

    </LinearLayout>
</layout>

1.BaseBindingAdapter

public abstract class BaseBindingAdapter<T, D extends ViewDataBinding> extends RecyclerView.Adapter<BaseViewHolder<D>> {

    private List<T> mDatas;
    private int layoutId;

    //用於設定Item的事件Presenter
    protected IBaseBindingPresenter ItemPresenter;

    public BaseBindingAdapter(List<T> mDatas, int layoutId) {
        this.mDatas = mDatas;
        this.layoutId = layoutId;
    }

    @Override
    public BaseViewHolder<D> onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        BaseViewHolder<D> viewHolder = new BaseViewHolder<D>((D) DataBindingUtil.inflate(inflater, layoutId, parent, false));
        onCreateViewHolder(viewHolder);
        return viewHolder;
    }

    public abstract void onCreateViewHolder(BaseViewHolder<D> holder);

    @Override
    public void onBindViewHolder(BaseViewHolder<D> holder, int position) {
        Log.i("tag", "onBindViewHolder");
        holder.getBinding().setVariable(BR.data, mDatas.get(position));
        holder.getBinding().setVariable(BR.itemPresenter, ItemPresenter);
        holder.getBinding().executePendingBindings();
    }

    @Override
    public int getItemCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    /**
     * 用於設定Item的事件Presenter
     *
     * @param itemPresenter
     * @return
     */
    public BaseBindingAdapter setItemPresenter(IBaseBindingPresenter itemPresenter) {
        ItemPresenter = itemPresenter;
        return this;
    }

}

2、點選事件處理介面:

public interface IBaseBindingPresenter {

}

3、BaseViewHolder:

public class BaseViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {

    protected final T binding;

    public BaseViewHolder(T t) {
        super(t.getRoot());
        this.binding = t;
    }

    public T getBinding() {
        return binding;
    }

}

4.在Activity中展示列表:

public class RecyclerBindActivity extends AppCompatActivity {

    private ActivityRecyclerBindBinding binding;

    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bind();
    }

    private void bind() {
        binding = DataBindingUtil.setContentView(this, R.layout.activity_recycler_bind);

        ArrayList<Student> students = getStudents();

        SimpleBindAdapter adapter = new SimpleBindAdapter(students, R.layout.item_recycler_view);
        adapter.setItemPresenter(new RecyclerBindPresenter());
        binding.recyclerView
                .setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        binding.recyclerView
                .setAdapter(adapter);
    }

    //presenter控制點選事件
    public class RecyclerBindPresenter implements IBaseBindingPresenter {

        public void onNameClick(Student student) {
            Toast.makeText(RecyclerBindActivity.this, student.name.get() + "要改名字", Toast.LENGTH_SHORT).show();
            student.name.set("我改名字啦!");
        }

        /**
         * 點選使用者年齡 += 3,且空間的左內邊距+=3;
         * {@link com.mei_husky.samplemvvm.view.bind.BindingUtil}
         */
        public void onAgeClick(Student student) {
            Toast.makeText(RecyclerBindActivity.this, String.valueOf("漲了三歲"), Toast.LENGTH_SHORT).show();
            student.setAge(student.getAge()+3);
        }
    }


    private ArrayList<Student> getStudents() {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("jack", 12));
        students.add(new Student("rose", 13));
        students.add(new Student("qingmei2", 18));
        students.add(new Student("unknown", 21));
        return students;
    }
}

5.建立BindUtil,處理點選age,paddingLeft+3的邏輯:

自定義 Setters
一些屬性需要自定義繫結邏輯,android:paddingLeft 屬性並沒有對應的setter方法,但是存在setPadding(left, top, right, bottom)方法。通過 BindingAdapter 註釋來自定義屬性呼叫的靜態setter方法。android 系統已經建立了 BindingAdapter 函式,下面是 paddingLeft 屬性對應的函式:

public class BindingUtil {

    /**
     * 該效果展示在->MainActivity ->Databinding展示列表 -> 點選item的Age按鈕
     * {@link com.mei_husky.samplemvvm.view.activity.RecyclerBindActivity}
     *
     * @param view
     * @param padding
     */
    @BindingAdapter("android:paddingLeft")
    public static void setPaddingLeft(View view, int padding) {
        view.setPadding(padding,
                view.getPaddingTop(),
                view.getPaddingRight(),
                view.getPaddingBottom());
    }
}

該註解的詳情,請看文末谷歌官方文件:

到此,列表展示,需求實現。

總結

總結一下實現方式:

1.我們建立BaseViewHolder和BaseAdapter(之後這步就可以直接跳過)

2.繪製xml佈局檔案,variable匯入datas資料和presenter響應事件

3.實現IBaseBindingPresenter介面自定義響應事件

4.activity中程式碼使用

其實看著可能有點頭暈,但是敲一遍就能明白了,其實程式碼中還有一點需要優化的,就是並沒有直接的方式在xml中給recyclerView設定Adapter和LayoutManager:

 <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        app:adapter = "@{presenter.adapter}"  //like this
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

但其實依賴上文中的@BindingAdapter註解,實現起來也是非常簡單,不贅述

我的其它文章:

參考文件:

本文中所有程式碼都已託管在GitHub上面:

該demo包含本文中所有程式碼但不僅限於:

使用了 Mvvm+DataBinding 搭建的DemoApp

1.MainActivity

-DataBinding的入門使用以及引導介面

2.DataBindingBaseActivity

-Databinding的所有基本使用方法

3.RecyclerBindActivity

-RecyclerView中使用dataBinding進行列表展示

4.MulTypeRecyclerBindActivity

-RecyclerView中使用dataBinding展示多型別列表