ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

35毫秒搞定10000个item:SpannedGridLayoutManager布局性能与缓存策略实战

2026/8/27 17:24:18 拓冰建站 浏览量
35毫秒搞定10000个item:SpannedGridLayoutManager布局性能与缓存策略实战 35毫秒搞定10000个itemSpannedGridLayoutManager布局性能与缓存策略实战【免费下载链接】SpannedGridLayoutManagerAndroid RecyclerView.LayoutManager that resizes and reorders views based on SpanSize项目地址: https://gitcode.com/gh_mirrors/sp/SpannedGridLayoutManagerSpannedGridLayoutManager 是一个基于 SpanSize 动态调整视图大小与顺序的 Android RecyclerView.LayoutManager。本文带你拆解它的布局性能设计为什么能在 35 毫秒内完成 10000 个 item 的布局计算以及 SpanSize 缓存、矩形缓存等缓存策略是如何一步步把布局开销压到最低的。一、它解决什么问题在瀑布流、混合尺寸网格这类场景中每个 item 的宽高跨度SpanSize都不同传统 GridLayoutManager 很难填满所有空隙。SpannedGridLayoutManager 通过自由矩形Free Rect分割算法自动为每个 item 找到合适的空位甚至会把后面的 item 提前填入空隙保证网格紧凑无洞。⚠️ 注意为了让网格填满空隙item 的视觉顺序可能与其在 Adapter 中的位置不一致这是设计使然。二、性能核心全量预计算 多级缓存1. 一次性算完所有 item 的位置在 SpannedGridLayoutManager.kt 的onLayoutChildren中布局流程是这样的遍历全部item为每个 item 计算 SpanSize 并找到对应的空闲矩形把每个 item 的矩形压入布局同时从空闲矩形列表中扣减空间只对视口内可见的 item 真正创建 View。也就是说纯计算与 View 创建分离10000 个 item 的坐标计算只是内存中的矩形运算而屏幕上同时存在的 View 可能只有几十个。这是35ms 搞定 10000 个 item的根本原因——它算的是数据不是视图。2. childFrames 帧缓存每个 item 算出最终位置后会被写入childFramesposition → Rect 的映射见 SpannedGridLayoutManager.kt#L298。之后测量子 View、获取带装饰的边距getDecoratedTop等方法都直接查这份缓存避免了重复的位置查找把 O(n) 的搜索降为 O(1)。3. SpanSizeLookup 的 SpanSize 缓存如果你的 SpanSize 计算逻辑很复杂比如要读模型字段、查配置可以开启缓存spanSizeLookup.usesCache true开启后每个 position 的 SpanSize 只会计算一次后续全部走 SparseArray 缓存。数据变化时调用invalidateCache()清空缓存即可。对于 50000 个 item 的场景这一步能省掉大量重复计算。4. rectsCache 矩形缓存RectsHelper内部维护了一份rectsCache见 SpannedGridLayoutManager.kt#L886-L888首次为某个 position 找到位置后再次查询直接返回缓存结果不会重新走矩形搜索流程。三、空闲空间分割算法图解核心算法很简单布局初始时只有一个覆盖全区域的自由矩形(0, 0, spans, Int.MAX_VALUE)。每放一个 item就把被占用的矩形从自由矩形中减掉最多切出左、上、右、下 4 个子矩形过滤掉被相邻矩形包含的冗余部分后重新排序。该算法的完整数学推导可参考项目内的 free_space_algorithm.pdf具体实现见RectsHelper的subtract方法。四、实测性能数据以下是官方在不同设备上的全量矩形预计算耗时单位 ms设备500 items1000 items10000 items50000 itemsAndroid 模拟器101835128OnePlus 3T1220135530OnePlus 6T51055200解读1 万 item 级别模拟器 35ms、中端真机 55ms 左右远低于一帧的 16ms 预算的 4 倍偶发的整表重排如notifyDataSetChanged完全可接受5 万 item 时耗时进入百毫秒级若配合无限滚动频繁触发整表重排建议考虑按批次计算矩形作者也在路线图中提及。五、性能调优清单复杂 SpanSize 必开缓存设置usesCache true数据更新后调用invalidateCache()避免无谓的全量重排只在数据真正变化时触发notifyDataSetChanged优先使用notifyItemChanged等细粒度刷新示例见 GridItemAdapter.kt;保持 SpanSize 稳定item 尺寸剧烈变化会触发大量重排与位置迁移滚动状态恢复默认关闭itemOrderIsStable false就是为了避免这类场景下的滚动异常超大列表留意整表重排成本5 万 item 以上建议分屏/分页加载减少单次onLayoutChildren的计算量。六、总结SpannedGridLayoutManager 的性能秘诀可以概括为一句话用数据预计算 多级缓存替代逐 View 布局。全量矩形预计算让坐标查找变成查表操作childFrames、rectsCache、SpanSize 缓存各司其职最终实现模拟器上 35ms 完成 1 万 item 布局的流畅体验。理解这套缓存策略对你优化任何 RecyclerView 自定义 LayoutManager 都有参考价值。【免费下载链接】SpannedGridLayoutManagerAndroid RecyclerView.LayoutManager that resizes and reorders views based on SpanSize项目地址: https://gitcode.com/gh_mirrors/sp/SpannedGridLayoutManager创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考