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" ); }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