Recyclerview 复用之headview优化
版本:support-v7 25.3.1
发现问题
在对 性能优化-首页CPU占用优化 调研时发现,首页的OnCreateViewHolder存在高频次调用的情况,而常见的开源列表组件不存在此问题。
遂针对此问题,对recyclerview的复用机制进行分析。
缓存集合
1 mChangedScrap 表示数据已经改变的ViewHolder集合
2 mAttachedScrap 与RecyclerView尚未分离的ViewHolder集合
3 mCachedViews ViewHolder缓存集合,默认为2。
4 mViewCacheExtension 开发者可自定义集合
5 mRecyclerPool ViewHolder缓存池。 被用来做下一级的缓存。默认最大为五个。
缓存复用流程
从onCreateViewHolder的调用开始看
tryGetViewHolderForPositionByDeadline方法,也是复用机制的重点。
这是一个自带过期时间的view复用函数,返回的对象如果时间不允许,那么可能会是null或者未绑定的。
dryRun 控制使用完缓存之后,是否需要从缓存中删除。
1 从被改变的废料中获取组件
如果这里是一个改变了的废料,那么使用getChangedScrapViewForPosition函数去获取。
// 0) If there is a changed scrap, try to find from there
来看具体的实现方法,
ViewHolder getChangedScrapViewForPosition(int position)
2 根据 position 从已经改变的废料集合中搜索缓存
如果成功,则打回。 第二步 根据id查询废料缓存。
3 从隐藏或者缓存的组件集合中获取 根据posotion
getScrapOrHiddenOrCachedHolderForPosition // 1) Find by position from scrap/hidden list/cache
这里做了两件事情,第一个从缓存列表中获取holder,然后在验证其有效性。
其实这里的getScrapOrHiddenOrCachedHolderForPosition 方法是缓存的重点功能实现。
4 从隐藏和缓存组件集合中获取,根据ids
从自定义的扩展中读取缓存
略,项目中未使用此功能。
从RecyclerPool读取缓存
这级别的是一个根据view type 进行缓存的SparseArray对象。
收获
1) 加深了对RecyclerView 缓存机制的理解
2) 问题定位:
项目中的headview的高度比itemview的高度,高出很多倍。 所以在 当head view被回收的时候,缓存中的itemview数量不足以复用,导致多次调用手动实例化方法。
3) 优化建议:
使用了headview的情况下,建议head view的高度不要比正常的item高度超过太多。
这样可以使item的使用完全可以通过缓存消化,避免频繁的手动实例布局文件。