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展示多型別列表