RecyclerView、ViewHolder和Adapter

首先,我们要明确这三个类各自的任务和逻辑结构。

RecyclerView 任务仅限于回收和定位屏幕上的 View ,RecyclerView 自身不会创建视图, 他通过 Adapter 创建。

Adapter 是一个控制器对象, 从模型层获取数据, 然后提供给 RecyclerView 显示,是沟通的桥梁。 他负责:

  1. 创建必要的 ViewHolder
  2. 绑定 ViewHolder 至模型层数据
    Adpater 与 RecyclerView 之间的桥梁
    Adpater 与 RecyclerView 之间的桥梁

ViewHolder 负责容纳 View 视图

ViewHolder 配合 RecyclerView 使用
ViewHolder 配合 RecyclerView 使用

使用 RecyclerView

1
2
mCrimeRecyclerView = view.findViewById(R.id.crime_recycler_view);
mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

当我们创建一个 RecyclerView 时, 我们首先要对他进行布局加载, 更要注意的是托管给 LayoutManager。没有 LayoutManager 的支持, 不仅 RecyclerView 无法正常工作, 还会导致应用崩溃。这是为什么呢?实际上, RecyclerView 不会亲自摆放屏幕上的列表项, 摆放的任务委托给了 LayoutManager。 LayoutManager 还负责定义屏幕上的滚动行为(竖着滚还是横着滚等等)

ViewHolder 显示视图

1
2
3
4
5
private class CrimeHolder extends RecyclerView.ViewHolder{
public CrimeHolder(LayoutInflater inflater, ViewGroup parent){
super(inflater.inflate(R.layout.list_item_crime, parent, false));
}
}

在 CrimeHolder 的构造方法中, 我们首先实例化list_item_crime布局,然后传给 super 方法, 也就是 ViewHolder 的构造方法。 基类ViewHolder 因而实际引用这个视图。

Adapter架起桥梁(绑定ViewHolder)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder>{

private List<Crime> mCrimes;

public CrimeAdapter(List<Crime> crimes){
mCrimes = crimes;
}

@Override
public int getItemCount() {
return mCrimes.size();
}

@NonNull
@Override
public CrimeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());

return new CrimeHolder(layoutInflater, parent);
}

@Override
public void onBindViewHolder(@NonNull CrimeHolder holder, int position) {
Crime crime = mCrimes.get(position);
//令每个ViewHolder绑定数据,具体bind函数略
holder.bind(crime);
}
}

RecyclerView 需要新的ViewHolder 来显示列表时,会调用 onCcreateViewHolder 方法。在这个方法内部, 我们创建一个 LayoutInflater, 然后用他创建 CrimeHolder。

CrimeAdapter 必须覆盖 onBindViewHolder 方法。
桥梁的具体过程:

  • 首先,调用 Adapter 的 getItemCount() 方法, RecyclerView 询问数组里列表中包含多少个对象。
  • 接着,RecyclerView 调用 Adapter 的 onCreateViewHolder(ViewGroup, int) 方法创建 ViewHolder 及其要显示的视图。
  • 最后,RecyclerView 会传入 ViewHolder 及其位置, 调用 onBindViewHolder(ViewHolder, int)方法。Adapter 会找到目标位置的数据并将其绑定到 ViewHolder 的视图上。所谓绑定,就是使用模型数据填充视图。

最后,别忘了关联 Adapter 和 RecyclerView

1
2
3
4
5
6
7
private void updateUI(){
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
mAdapter = new CrimeAdapter(crimes);
//将具体的 RecyclerView 和 Adapter 关联到一起
mCrimeRecyclerView.setAdapter(mAdapter);
}