• 面试:List View和RecyclerView缓存策略对比


    相关推荐:

    RecyclerView 面试题 | 哪些情况下表项会被回收到缓存池? - 掘金

    Listview的二级缓存

    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。

    在这里插入图片描述

    ListView 怎么进行优化的?

    ConvertView重用机制:在getView()方法中使用ConvertView,不需要每次都inflate一个View出来,这样既浪费时间又浪费内存。
    Viewholder机制:使用Viewholder,避免在getView()方法频繁调用去使用findViewById方法,节省时间和内存。
    分页加载:每加载一页的数据就覆盖上一页的数据。
    数据中有图片:使用第三方库(三级缓存机制)

    1. @Override
    2. public View getView(int position, View convertView, ViewGroup viewGroup) {
    3. LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
    4. if (getItemViewType(position) == ViewType.TEXT){
    5. if (convertView == null){
    6. convertView = inflater.inflate(R.layout.text_message_item,viewGroup,false);
    7. }
    8. TextView textView = convertView.findViewById(R.id.message_content);
    9. TextMessage textMessage = (TextMessage)messageList.get(position);
    10. textView.setText(textMessage.getText());
    11. }else {
    12. if (convertView == null){
    13. convertView = inflater.inflate(R.layout.image_message_item,viewGroup,false);
    14. }
    15. ImageView imageView = convertView.findViewById(R.id.image_head);
    16. ImageMessage imageMessage = (ImageMessage)messageList.get(position);
    17. imageView.setImageResource(imageMessage.getImage());
    18. }
    19. return convertView;
    20. }

    RecyclerView的四级缓存

    RecycleView的四级缓存是由三个类共同作用完成的,Recycler、RecycledViewPool和ViewCacheExtension。

    一、Recycler

    ​ 用于管理已经废弃或者与RecyclerView分离的ViewHolder

    1.屏幕内缓存 一级缓存,屏幕内缓存指在屏幕中显示的ViewHolder,这些ViewHolder会缓存在AttachedScrap、ChangedScrap中

    2.屏幕外缓存 二级缓存,当列表滑动出了屏幕时,ViewHolder会被缓存在 CachedViews ,其大小由ViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,可通过Recyclerview.setItemViewCacheSize()动态设置。

    二级缓存保存最近移出屏幕的ViewHolder,包含数据和position信息,复用时必须是相同位置的ViewHolder才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用ViewHolder数据,不需要重新bindView。用一个数组保存ViewHolder,实现是:ArrayList mCachedViews

    二、RecycledViewPool

    RecyclerView 面试题 | 哪些情况下表项会被回收到缓存池? - 掘金

    ​三级缓存, RecycledViewPool类是用来缓存ViewHolder。缓存池是所有缓存中速度最慢的,其中的ViewHodler是脏的,得重新执行onBindViewHolder()哪些情况下“表项会被回收到缓存池:

    1、表项主动移出屏幕:item 1 和 2 移出屏幕时,正好填满mCachedViews,当 item 3 移出屏幕时,item 1 就被挤出并存入缓存池。

    2、表项被挤出屏幕

    3、 高速缓存命中的 ViewHolder 变脏:

    RecyclerView 中有四级缓存,它会优先去一级缓存中找 ViewHolder 实例。缓存池是其中速度最慢的,因为从中取出的 ViewHolder 需要重新执行onBindViewHolder()scrapview cache的速度都比它快,但命中后需要进行额外的校验

    4、mCachedViews 中缓存的表项被删除:表项移出屏幕后,立刻被回收到mCachedViews结构中。若恰巧该表项又被删除了,则表项对应的 ViewHolder 从mCachedViews结构中移除,并添加到缓存池中

    缓存池,当cacheView满了后,将cacheView中移出的ViewHolder放到Pool中,放之前会把ViewHolder数据清除掉,所以复用时需要重新bindView。实现是: SparseArray> mScrap;//按viewType来保存ViewHolder,每种类型最大缓存个数默认为5
     

    RecyclerView缓存过程:

    RecyclerView性能优化及高级使用_潇潇凤儿的博客-CSDN博客_recyclerview优化方案

    在滑动过程中,会先滑动的itemView保存到CacheView中,CacheView大小默认是2,如果超过了最大容量,则按FIFO,将队列头部的itemView出队,保存至缓存池RecyclerViewPool中,缓存池是按itemView的类型itemType来保存的,每种itemType默认缓存个数是5,超过了,则直接由GC回收。具体表现如下图:

    可以看到CacheView缓存中蓝色的块一直最最近两个,而RecycledViewPool中,保存最大是5,超过5了后ViewHolder都被回收。

    RecyclerView缓存寻找过程:

    RecyclerView在找到可用ViewHodler的顺序是:如果在缓存CacheViews中找到,则直接复用;如果在缓存池RecycerViewPool找到,则需要bindView;如果没有找到可用的ViewHolder,则需要create新建一个ViewHolder,并bindView绑定view。

    三、ViewCacheExtension

    四级缓存, 开发者可自定义的一层缓存,是虚拟类ViewCacheExtension的一个实例,开发者可实现方法getViewForPositionAndType(Recycler recycler, int position, int type)来实现自己的缓存。

     RecyclerView的缓存和复用由Recycler实现,mAttachedScrap和mCachedViews的缓存方式跟ListView相似。mRecyclerPool是多个RecyclerView的复用池,mViewCacheExtension不直接使用,需要用户再定制,默认不实现。

    1. public final class Recycler {
    2. final ArrayList mAttachedScrap = new ArrayList<>();
    3. final ArrayList mCachedViews = new ArrayList();
    4. RecycledViewPool mRecyclerPool;
    5. private ViewCacheExtension mViewCacheExtension;
    6. }

    总结

    ListView二级缓存

     RecyclerView四级缓存

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

    Android 实习生面试经历记录_code小生_的博客-CSDN博客

  • 相关阅读:
    Ceres Solver简介及使用
    视频集中存储EasyCVR平台播放一段时间后出现黑屏是什么原因?该如何解决?
    极简二叉树
    CSP-J/S信息学奥赛-算法
    仿牛客网项目---消息队列的实现
    如何创建集成 LSP 支持多语言的 Web 代码编辑器
    [oeasy]python0013_ASCII码表_英文字符编码_键盘字符
    CSDN21天学习挑战赛 - 第一篇打卡文章
    JMeter性能测试之使用CSV文件参数化
    基于java的学生信息管理系统
  • 原文地址:https://blog.csdn.net/cpcpcp123/article/details/127704868