recyclerview的回收、缓存机制

689 阅读4分钟

前言

本篇文章说是讲解回收、缓存机制的,但是实际上我还是把recycleview各种场景以及跟listview对比都整理了,目的是希望这一篇文章尽量能把日常碰到的各种问题全部搞定.

listView剖析

1.BaseAdapter详解

这个随便参考一篇博客就好了,如Android BaseAdapter 和ListAdapter的介绍,不过多描述,我之前主要是容易把listAdapter跟baseAdapter搞混,实际上他俩是继承关系.

2.listview源码分析

说实话我之前并没有看过源码,现在也没所以这篇文章我主要是做tag,有兴趣自己参考listview源码分析

3.Recycleview和listview区别

RecyclerView 和 ListView 使用对比分析,随便看看就好了.

recyclerview剖析

剖析recyclerview之前我们先把常用面试会问到的问题列举下.

问题1:ViewHolder 为什么要被声明成静态内部类

参考这篇文章ViewHolder 为什么要被声明成静态内部类 即可.核心一点其实就是viewHolder是内部类,不用静态会存在内存泄露的场景

问题2.ListView & RecycleView 如何进行局部刷新的

ListView参考如何对 ListView & RecycleView 进行局部刷新的

recycleview刷新建议看这篇RecycleView 详细进行局部刷新 ,注意一点,payload这个参数值真的只是纯粹的一个标记.
核心思想:
无非是我们默认更新走的是recyclerViewAdapter.notifyItemChanged(position)
实际上我们改调用notifyItemRangeChanged(int positionStart, Object payload)
同时重写adapter中的onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads)

问题3:listview & RecycleView加载图片错位,以及如何解决的

android listview图片错位原理及解决方法 ,例如这篇文章我个人觉得写的是有问题的,感觉没有搞清楚复用的机制,我们往下滑动数据的时候,是先从缓存里那(listview是存在二级缓存的,第二层缓存默认容量其实只有2的大小),如果拿不到是会创建新viewHolder的,最后才是把移除屏幕的item进行缓存的,RecyclerView同理,区别主要是RecyclerView是四级缓存数据.

那么真实的图片错位的原因是什么样呢?我因为主要是研究RecyclerView,所以拿它举例.按理来说要理解这种情况,是需要先了解recyclerview的回收、缓存机制的 关于RecyclerView使用Glide加载图片导致错位问题:这个问题我本来是打算从网上找篇合适的文章引用,实际上发现网上写的我个人感觉都是有问题的,没有把错位讲清楚. 图画的少,见怪.
1.新数据进入屏幕,会先从第二级缓存里面拿数据(会进行postion比较,必须得相等),如果拿不到合适的viewHolder,那就去缓存池里面取viewHolder(这个viewHolder是重置了,拿到就行,重新赋值),还是取不到就要创建新的viewHolder
2.新数据进入屏幕的同时老数据会移除屏幕,移除屏幕的数据会先进入二级缓存(默认最大2个,可手动设置大小),如果二级缓存满了,会把二级缓存数据先进先出 进入到缓存池里,移除屏幕的数据进入二级缓存
3.所以随着第1、2、3、4、5、6、7个等等移除屏幕的时候,缓存池必定存在缓存的viewHolder的postion为7(可能也是6 不太记得了),此刻当最新数据进入屏幕,先从缓存池拿viewHolder(通过比较显示在屏幕中显示的postion位置而不是在数据中的位置)会发现能拿到合适的viewHolder,而二级缓存里面的viewHolder还维持着数据的值,如果新数据是异步加载需要时间的,如果异步加载还没成功,我们就很有可能用到旧的数据,最常见的就是图片.

处理办法,一般

// 给 ImageView 设置一个 tag
holder.img.setTag(imgUrl);
// 预设一个图片
holder.img.setImageResource(R.drawable.ic_launcher);

// 通过 tag 来防止图片错位
if (imageView.getTag() != null && imageView.getTag().equals(imageUrl)) {
    imageView.setImageBitmap(result);

问题4:recycleview闪烁、卡顿处理、性能优化

RecycleView 性能提升、卡顿、闪烁、优化(绝对干货!!) 绝对的好文,这篇文章就够了

问题5:Recycleview优缺点

后续再补,暂时可参考Android RecyclerView的使用及和ListView比较的优缺点

问题6:如何给 ListView & RecyclerView加上拉刷新 & 下拉加载更多机制

后续再补

问题6:recyclerView 的回收、复用机制(重点!!!)

结合源码跟这篇文章RecyclerView 的回收、复用机制还有让你彻底掌握RecyclerView的缓存机制 ,看个大概吧,大体原理就基本上知道了, 入口是在滑动跟踪源码(ontouchEvent方法里面),我个人可能后续还是要自己写下源码分析,现在因为准备面试,感觉时间上比较紧张. 根据滑动跟踪源码

onTouchEvent
Move
	scrollByInternal
		mLayout.scrollVerticallyBy(y, mRecycler, mState);
			LinearLayoutManager.scrollBy();
				 fill(recycler, mLayoutState, state, false);
 fill(recycler, mLayoutState, state, false);
 	recycleByLayoutState(recycler, layoutState);//回收
 			recycler.recycleViewHolderInternal()//回收主要方法
 	layoutChunk(recycler, state, layoutState, layoutChunkResult);//复用
 		layoutState.next(recycler);
 			 recycler.getViewForPosition(mCurrentPosition);
第一级:mChangedScrap 与 mAttachedScrap  ---> 回收:recycler.scrapView(view);
第二级:mCachedViews---》 默认大小为2 ---》 回收:recycler.recycleViewHolderInternal()
第三级:mViewCacheExtension
第四级:pool ---》 默认大小5

后记

这个其实细看下来也不简单,后面我一定会补充完整.