对RecyclerView的一点探讨

1.RecyclerView简要介绍

RecyclerView是ListView的升级版,Google的介绍是A flexible view for providing a limited window into a large data set(一个能够灵活的为有限的窗口填充大量数据的View),它比LisView更加灵活,使用起来也更加方便,更多介绍戳RecyclerView文档 RcyclerView使用也很简单,主要有以下三个元素:

1、RecyclerView.Adapter,与ListView中的Adapter类似,不过需要使用到ViewHolder。

2、LayoutManager,管理View位置、View的复用等众多功能。

3、ItemAnimator,在Adapter收到变动的通知后,用动画显示View的变动。

关于RecyclerView的基本使用就不做详细介绍,推荐一篇文章,Android中的RecyclerView: 基础知识

2.RecyclerView中view和viewholder的缓存机制

ListView使用了viewholder提升性能,作为ListView的升级版,RecyclerView同样使用了viewholder缓存从而提升性能,缓存原理与ListView类似。参考关于RecyclerView中Viewholder和View的缓存机制的探究这篇文章,自己也写了一个Test Demo测试RecyclerView在包含单种及多种type的item view的情况下的缓存情况。

首先,创建RecyclerViewAdapter类,此类为RecyclerView使用过程中需要的Adapter,用于测试拥有不同type的item view情况下缓存机制。代码如下:

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
public class RecyclerViewAdapter extends RecyclerView.Adapter.RecyclerViewAdapter.ViewHolder {
private final static int TYPE_0 = 0;
private final static int TYPE_1 = TYPE_0 + 1;
private final static int TYPE_2 = TYPE_1 + 1;
private final int typeCount;
public RecyclerViewAdapter(int typeCount){
if(typeCount == 1){
this.typeCount = 1;
}else if(typeCount == 3){
this.typeCount = 3;
}else{
this.typeCount = typeCount;
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (getItemViewType(viewType) == TYPE_0){
Log.i("RecyclerViewAdapter", "onCreateViewHolder()--TYPE_0");
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_1, parent, false);
}else if (getItemViewType(viewType) == TYPE_1){
Log.i("RecyclerViewAdapter", "onCreateViewHolder()--TYPE_1");
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_2, parent, false);
}else {
Log.i("RecyclerViewAdapter", "onCreateViewHolder()--TYPE_2");
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_3, parent, false);
}
return new ViewHolder(view, getItemViewType(viewType));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (getItemViewType(position) == TYPE_0){
Log.i("RecyclerViewAdapter", "onBindViewHolder()--TYPE_0");
holder.textView.setText(position + "");
}else if (getItemViewType(position) == TYPE_1){
Log.i("RecyclerViewAdapter", "onBindViewHolder()--TYPE_1");
// holder.imageview.setImageResource(R.drawable.ic_launcher);
}else {
Log.i("RecyclerViewAdapter", "onBindViewHolder()--TYPE_2");
holder.button.setText(position + "");
}
}
@Override
public int getItemCount() {
if (typeCount == 1){
return 24;
}else if (typeCount == 2){
return 36;
}
return 42;
}
@Override
public long getItemId(int position) {
return super.getItemId(position);
}
@Override
public int getItemViewType(int position) {
if (typeCount == 1){
return TYPE_0;
}else if (typeCount == 2){
return position % 2 == 0 ? TYPE_0 : TYPE_1;
}else {
if (position % 3 == 0){
return TYPE_0;
}else if (position % 3 == 1){
return TYPE_1;
}else {
return TYPE_2;
}
}
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView textView;
ImageView imageview;
Button button;
public ViewHolder(View view, int type){
super(view);
switch (type){
case 0:
textView = (TextView) view.findViewById(R.id.textview);
break;
case 1:
imageview = (ImageView) view.findViewById(R.id.image);
break;
case 2:
button = (Button) view.findViewById(R.id.button);
break;
default:
break;
}
}
}
}

此类测试最多情况下包含了三种type的View,在构造函数中,只需要传入需要测试的type的数量(1<=type<=3)。

然后传入不同的typeCount值进行测试,传入typeCount = 1时测试代码如下,其他情况类似。

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
public class Fragment1 extends Fragment {
private View mView;
private RecyclerView mRecyclerView;
private LinearLayoutManager linearLayoutManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_1, null);
initView();
return mView;
}
private void initView(){
if (mView == null){
return;
}
linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView = (RecyclerView) mView.findViewById(R.id.rv_1);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(new RecyclerViewAdapter(1));
}
}

测试结果:

当RecyclerView的android:layout_height属性设置为match_parent时,只为RecyclerView设置一种类型的item view,结果是:

屏幕中最多能显示5个item view,创建了7个ViewHolder,创建的个数为屏幕最多显示item view的个数+2;

接着重新设置RecyclerView的android:layout_height属性为400dp,得出结果如下:

屏幕中最多能显示4个item view,共创建了6个ViewHolder,同样是屏幕最多显示item view的个数+2。

得出结论:当只有一种类型的item view的情况下,缓存创建的ViewHolder的个数为屏幕最多显示item view的个数+2,与关于RecyclerView中Viewholder和View的缓存机制的探究文章的结论一致。

接着,我们为RecyclerView设置2种类型的item view,RecyclerView的android:layout_height属性设置为match_parent,发现此时两种类型的item view,type1和type2,在屏幕中均最多只能显示3个,而分别为两种类型创建了4个ViewHolder,创建的ViewHolder个数为屏幕最多显示item view的个数+1;这是不是一种特殊情况?接着,我们改变条件,为RecyclerView设置3种类型的item view,测试结果如下:

3种类型的item view在RecyclerView中显示,每种类型均最多显示2个,每种类型分别创建的ViewHolder个数为3个,与上面的出的结论吻合。我们暂定结论为:当有多种类型(>=2)的item view在RecyclerView中显示,每种类型的item view缓存创建的ViewHolder个数为其在屏幕中最多显示item view的个数+1;

然后,我们再次改变条件,设置RecyclerView的android:layout_height属性为400dp,向RecyclerView中设置两种类型的item view,结果同样满足上面暂定得出的结论。

因此,得出结论:当有多种类型(>=2)的item view在RecyclerView中显示,每种类型的item view缓存创建的ViewHolder个数为其在屏幕中最多显示item view的个数+1,同样与关于RecyclerView中Viewholder和View的缓存机制的探究文章的结论一致。

3.总结

通过测试,得出以下结论:

a.调用onCreateViewHolder(ViewGroup parent, int viewType)创建ViewHolder;

b.滚动过程中,每次通过调用onBindViewHolder(ViewHolder holder, int position)绑定更新数据;

c.当只有一种类型的item view的情况下,缓存创建的ViewHolder的个数为屏幕最多显示item view的个数+2;

d.当有多种类型(>=2)的item view在RecyclerView中显示,每种类型的item view缓存创建的ViewHolder个数为其在屏幕中最多显示item view的个数+1。

文章参考:Android中的RecyclerView: 基础知识关于RecyclerView中Viewholder和View的缓存机制的探究

源码:https://gitlab.com/lujun/TestRecyclerView