相关推荐:
RecyclerView 面试题 | 哪些情况下表项会被回收到缓存池? - 掘金
ListView 是怎么实现 RecycleBin 并更新 View 的?
在 Adapter 中的 getView()方法中执行 LayoutInflater.inflate()方法是很消耗资源的,所以ListView通过 RecycleBin 去维护两个数组 mActiveViews 和mScrapViews 用来进行 view 的复用工作。具体是在绘制 view 的(measure->layout->draw)的 layout 过程中实现。
举个例子,某一时刻ListView中显示10个子View,position依次是0-9,这时下滑,ListView需要绘制下一帧,这时候ListView在layoutchildren方法中把这10个子View都存入了mActiveViews数组中,然后清空children数组,调用filldown方法,向listview中依次添加position 1到10的子view,在填充1-9时,由于在上一帧position=1-9的view已经被放入了mActiveViews数组中,因此可以直接将其从数组中取出,直接复用。如果没能够从mActivieViews中直接复用View,那么就要调用obtainView方法获取View,该方法尝试间接复用RecycleBin中的mScrapViews中的View,如果不能间接复用,则创建新的View。
ListView的缓存和复用由它的父类AbsListView中的RecycleBin实现,设了两个缓存数组mActiveViews和mScrapViews。mActiveViews缓存显示在屏幕中的view,mScrapViews按ViewType缓存离屏的view
RecycleBin作为实现类:通过两级缓存来缓存view。
ActiveViews存储的是layout开始的时候屏幕上那些view。layout结束后,所有ActiveViews中的view被移动到ScrapViews中。
ScrapViews中的views是那些可能被adapter重新用到的view,以避免重新创建不必要的view。


①ConvertView重用机制:在getView()方法中使用ConvertView,不需要每次都inflate一个View出来,这样既浪费时间又浪费内存。
②Viewholder机制:使用Viewholder,避免在getView()方法频繁调用去使用findViewById方法,节省时间和内存。
③分页加载:每加载一页的数据就覆盖上一页的数据。
④数据中有图片:使用第三方库(三级缓存机制)
- @Override
- public View getView(int position, View convertView, ViewGroup viewGroup) {
- LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
- if (getItemViewType(position) == ViewType.TEXT){
- if (convertView == null){
- convertView = inflater.inflate(R.layout.text_message_item,viewGroup,false);
- }
- TextView textView = convertView.findViewById(R.id.message_content);
- TextMessage textMessage = (TextMessage)messageList.get(position);
- textView.setText(textMessage.getText());
- }else {
- if (convertView == null){
- convertView = inflater.inflate(R.layout.image_message_item,viewGroup,false);
- }
- ImageView imageView = convertView.findViewById(R.id.image_head);
- ImageMessage imageMessage = (ImageMessage)messageList.get(position);
- imageView.setImageResource(imageMessage.getImage());
- }
- return convertView;
- }
RecycleView的四级缓存是由三个类共同作用完成的,Recycler、RecycledViewPool和ViewCacheExtension。
用于管理已经废弃或者与RecyclerView分离的ViewHolder
1.屏幕内缓存 一级缓存,屏幕内缓存指在屏幕中显示的ViewHolder,这些ViewHolder会缓存在AttachedScrap、ChangedScrap中
2.屏幕外缓存 二级缓存,当列表滑动出了屏幕时,ViewHolder会被缓存在 CachedViews ,其大小由ViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,可通过Recyclerview.setItemViewCacheSize()动态设置。
二级缓存保存最近移出屏幕的ViewHolder,包含数据和position信息,复用时必须是相同位置的ViewHolder才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用ViewHolder数据,不需要重新bindView。用一个数组保存ViewHolder,实现是:ArrayList
RecyclerView 面试题 | 哪些情况下表项会被回收到缓存池? - 掘金
三级缓存, RecycledViewPool类是用来缓存ViewHolder。缓存池是所有缓存中速度最慢的,其中的ViewHodler是脏的,得重新执行onBindViewHolder()哪些情况下“表项会被回收到缓存池:
1、表项主动移出屏幕:item 1 和 2 移出屏幕时,正好填满mCachedViews,当 item 3 移出屏幕时,item 1 就被挤出并存入缓存池。
2、表项被挤出屏幕
3、 高速缓存命中的 ViewHolder 变脏:
RecyclerView 中有四级缓存,它会优先去一级缓存中找 ViewHolder 实例。缓存池是其中速度最慢的,因为从中取出的 ViewHolder 需要重新执行onBindViewHolder()。scrap和view cache的速度都比它快,但命中后需要进行额外的校验
4、mCachedViews 中缓存的表项被删除:表项移出屏幕后,立刻被回收到mCachedViews结构中。若恰巧该表项又被删除了,则表项对应的 ViewHolder 从mCachedViews结构中移除,并添加到缓存池中
缓存池,当cacheView满了后,将cacheView中移出的ViewHolder放到Pool中,放之前会把ViewHolder数据清除掉,所以复用时需要重新bindView。实现是: SparseArray
RecyclerView性能优化及高级使用_潇潇凤儿的博客-CSDN博客_recyclerview优化方案
在滑动过程中,会先滑动的itemView保存到CacheView中,CacheView大小默认是2,如果超过了最大容量,则按FIFO,将队列头部的itemView出队,保存至缓存池RecyclerViewPool中,缓存池是按itemView的类型itemType来保存的,每种itemType默认缓存个数是5,超过了,则直接由GC回收。具体表现如下图:

可以看到CacheView缓存中蓝色的块一直最最近两个,而RecycledViewPool中,保存最大是5,超过5了后ViewHolder都被回收。
RecyclerView在找到可用ViewHodler的顺序是:如果在缓存CacheViews中找到,则直接复用;如果在缓存池RecycerViewPool找到,则需要bindView;如果没有找到可用的ViewHolder,则需要create新建一个ViewHolder,并bindView绑定view。
四级缓存, 开发者可自定义的一层缓存,是虚拟类ViewCacheExtension的一个实例,开发者可实现方法getViewForPositionAndType(Recycler recycler, int position, int type)来实现自己的缓存。
RecyclerView的缓存和复用由Recycler实现,mAttachedScrap和mCachedViews的缓存方式跟ListView相似。mRecyclerPool是多个RecyclerView的复用池,mViewCacheExtension不直接使用,需要用户再定制,默认不实现。
- public final class Recycler {
- final ArrayList
mAttachedScrap = new ArrayList<>(); - final ArrayList
mCachedViews = new ArrayList(); - RecycledViewPool mRecyclerPool;
- private ViewCacheExtension mViewCacheExtension;
- }

ListView二级缓存

RecyclerView四级缓存

【Android面试】Listview和Recyclerview的区别_Rose J的博客-CSDN博客_android listview和recyclerview Android:ListView 和RecyclerView区别 - 夜空中最亮的盖子 - 博客园