RecyclerViewBaseAdapter基础封装

RecycelrViewAdapter的封装

It’s well known that RecyclerView is a powerful tool to create a list view or a grid view, however, it’s also complicated to use.

There’s a passage I writed a few months ago, in this passage I used an example to show the basic usage of RecyclerView.
—>RecyclerView基础用法

So in my opinion, there are six steps to use RecyclerView.

  • Add dependecy of RecyclerView
  • Create an activity/fragment, and use the control in it’s layout file.
  • Create an item, which is the model of your every list’s view.
  • Create a class as a model, which contains the information that is needed in every item.
  • Create an adapter.
  • Use it in your activity or fragment.

The most important step is step 5, an adapter is so complicated to create. So how can we solve the problem?

There is a princple in Java: High cohesion, low coupling,so we would better to separate the viewHolder from RecyclerViewAdapter
So first, we can create a base adapter.

BaseRecyclerViewAdapter

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
public abstract class BaseRecyclerViewAdapter<Data> extends RecyclerView.Adapter<BaseViewHolder> {


protected List<Data> mDataList;
protected Context mContext;
protected LayoutInflater mInflater;
protected int mItemLayoutId;
private OnItemClickListener mOnItemClickListener;


public BaseRecyclerViewAdapter(List<Data> dataList, Context context, @LayoutRes int itemLayoutId) {
mDataList = dataList;
mContext = context;
mInflater = LayoutInflater.from(mContext);
mItemLayoutId = itemLayoutId;
}

@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v, mDataList.get(position), position);
}

}
});
bindView(holder, mDataList.get(position));
}


/**
* 绑定item中的view和数据
*
* @param viewHolder
* @param item
*/
protected abstract void bindView(BaseViewHolder viewHolder, Data item);


@Override
@SuppressWarnings("unchecked")
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(mItemLayoutId, parent, false);
return new BaseViewHolder(mContext, view);
}


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

/**
* 设置数据
*
* @param data 数据
*/
public void setDataList(Collection<Data> data) {
this.mDataList.clear();
this.mDataList.addAll(data);
notifyDataSetChanged();
}

/**
* 获取当前列表的数据
*/
public List<Data> getDataList() {
return this.mDataList;
}

/**
* 添加数据
*
* @param data
*/
public void addItem(Data data) {
this.mDataList.add(data);
notifyDataSetChanged();
}


/**
* @param collection
*/
public void addItems(Collection<Data> collection) {
this.mDataList.addAll(collection);
notifyDataSetChanged();
}


/**
* 移除数据
*
* @param data 移除的数据
*/
public void removeItem(Data data) {
this.mDataList.remove(data);
notifyDataSetChanged();
}


/**
* 移除数据(带动画)
*
* @param position pos
*/
public void removeItem(int position) {
this.mDataList.remove(position);
//该方法不会使position及其之后位置的itemView重新onBindViewHolder
notifyItemRemoved(position);
//所以需要从position到列表末尾进行数据刷新
notifyItemRangeChanged(position, mDataList.size() - position);

}

/**
* 清除全部数据
*/
public void removeAllItem() {
mDataList.clear();
notifyDataSetChanged();
}

/**
* 获取position 处数据
*/
public Data getItem(int position) {
return mDataList.get(position);
}

/**
* 刷新页面
*/
public void refresh() {
notifyDataSetChanged();
}

public void refresh(int position) {
notifyItemChanged(position);
}

public interface OnItemClickListener<Data> {

/**
* 点击事件回调
*
* @param view
* @param position
*/
public void onItemClick(View view, Data data, int position);
}

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}

}

So We just look at the basic ones.
It’s obviou that in the class we override the three classic methods–onCreateViewHolder(),onBindViewHolder(),getItemCount();
First, we create a ViewHolder

1
2
3
4
5
6
@Override
@SuppressWarnings("unchecked")
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(mItemLayoutId, parent, false);
return new BaseViewHolder(mContext, view);
}

Then we will bind the holder to the data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v, mDataList.get(position), position);
}

}
});
bindView(holder, mDataList.get(position));
}

we also set clicklistener to the item
We don’t directly bind the data to the view because we don’t exactly know how many data,how many controls need to be binded, so we should define an abstract method to be override in different situation. That’s why we use the bindView().

So we just need to override two methods–the constuction methond of your class and the bindView() if we want to use it in subclass.

The getItemCount() is so easy that we don’t talk about it.


BaseViewHolder

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142


public class BaseViewHolder extends RecyclerView.ViewHolder {


private final SparseArray<View> mViewSparseArray;
private Context mContext;
private View mItemView;


public BaseViewHolder(Context context, View itemView) {
super(itemView);
this.mContext = context;
mItemView = itemView;
mViewSparseArray = new SparseArray<>();
}


/**
* 从布局获取泛型view
*
* @param viewId
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
protected <T extends View> T findViewById(@IdRes int viewId) {
//从已经缓存的ViewMap中查找
View view = mViewSparseArray.get(viewId);
//如果没有缓存
if (view == null) {
//获取实例并加入缓存
view = mItemView.findViewById(viewId);
mViewSparseArray.append(viewId, view);
}
return (T) view;
}


/**
* 设置TextView类型
*
* @param viewId
* @param value
* @return
*/
public BaseViewHolder setText(@IdRes int viewId, @StringRes int value) {
return setText(viewId, mContext.getString(value));
}

public BaseViewHolder setText(@IdRes int viewId, String value) {
TextView textView = findViewById(viewId);
textView.setText(value == null ? mContext.getString(R.string.empty) : value);
return this;
}


/**
* 设置ImageView的url
*
* @param viewId
* @param value
* @return
*/
public BaseViewHolder setImgUrl(@IdRes int viewId, String value) {
ImageView imageView = findViewById(viewId);
if (value != null) {
Glide.with(mContext)
.load(value)
.transition(GenericTransitionOptions.<Drawable>withNoTransition())
.into(imageView);
}
return this;
}


/**
* 设置ImageView的url
*
* @param viewId
* @return
*/
public BaseViewHolder setImgRes(@IdRes int viewId, @DrawableRes int drawableId) {
ImageView imageView = findViewById(viewId);
imageView.setImageResource(drawableId);
return this;
}


/**
* 设置控件是否可见
*
* @param viewId
* @param isVisible
* @return
*/
public BaseViewHolder setVisible(@IdRes int viewId, boolean isVisible) {
findViewById(viewId).setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
return this;
}

/**
* 设置控件是否消失(不保留空间)
*
* @return
*/
public BaseViewHolder setGone(@IdRes int viewId) {
findViewById(viewId).setVisibility(View.GONE);
return this;
}

/**
* 获取item的View
*
* @return
*/
public View getItemView() {
return mItemView;
}

/**
* 获取item内部的view
*
* @param viewId
* @return
*/
public View getViewById(@IdRes int viewId) {
return findViewById(viewId);
}


/**
* 获取当前viewHolder位置
*
* @return
*/
public int getViewHolderPosition() {
return getAdapterPosition();
}


}

The annotate is so clear, from the code of BaseRecyclerViewAdatper we can know that if we want to use the methond bindView(), we should put the parameters of viewHolder which is the type of BaseViewHolder, so in the method, we can use the methods of viewHolder such as setTxt(), setImageRes() to bind the controls the view.

1
2
3
4
5
6
7
/**
* 绑定item中的view和数据
*
* @param viewHolder
* @param item
*/
protected abstract void bindView(BaseViewHolder viewHolder, Data item);

So how easy the way to use RecyclerViewAdapter can be if we use the BaseRecyclerViewAdapter? Don’t worry, there is an example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CantDoListAdapter extends BaseRecyclerViewAdapter<CalendarModel.BadBean> {
public CantDoListAdapter(List<CalendarModel.BadBean> badBeanList, Context context, int itemLayoutId) {
super(badBeanList, context, itemLayoutId);

}

@Override
protected void bindView(BaseViewHolder viewHolder, CalendarModel.BadBean item) {
viewHolder.setText(R.id.item_calendar_can_do,item.getTitle())
.setText(R.id.item_calendar_can_do_detail,item.getDescription());
ImageView imageView = (ImageView)viewHolder.getItemView().findViewById(R.id.item_image_flag);
imageView.setBackgroundColor(mContext.getResources().getColor(R.color.red));
}
}

Is so easy, isn’t it?

-------------本文结束感谢您的阅读-------------