资讯动态

【Android面试】RecylerView专题

发布时间:2026/10/19 1:35:31 来源:尧图企业网站定制
文章目录一、基础原理与复用缓存1. RecyclerView 与 ListView 的核心区别是什么2. 四级缓存mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool各自作用、优先级与降级策略不同滑动 / 刷新场景的命中逻辑3. mAttachedScrap 与 mCachedViews 的本质区别为何 detach 而非 remove4. ViewHolder 定义、复用触发条件、创建时机放入 RecycledViewPool 的条件如何自定义复用池大小与策略5.onBindViewHolder 重复调用的原因及优化方案6. 预取Prefetch机制原理、LinearLayoutManager 预取距离 / 数量计算逻辑7. mAttachedScrap和mChangedScrap的区别二、LayoutManager 布局1. LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager 的布局逻辑差异2. onLayoutChildren 完整执行流程锚点定位、填充、回收自定义 LayoutManager 如何处理异常布局5. 自定义 LayoutManager 核心方法measureChild、layoutDecorated、scrollVerticallyBy/scrollHorizontallyBy作用dx/dy 如何正确消费6. GridLayoutManager Span 分配机制动态 SpanSize 布局冲突解决方案7. 实现多布局的思路无限循环 LayoutManager 需规避的边界问题三、Adapter 与数据刷新8. notifyDataSetChanged、notifyItemChanged、notifyItemRangeChanged 的区别与性能影响9. DiffUtil 核心算法Myers原理、时间 / 空间复杂度自定义 DiffUtil.Callback 方式10.AsyncListDiffer 异步计算逻辑、线程池策略如何避免主线程阻塞11. payload 精准局部刷新原理12. notifyItemMoved 底层实现为何移动操作会导致其他 Item 重复 bind13. RecylerView实现局部刷新的原理四、分割线、动画与交互13. 自定义 ItemDecoration 核心方法getItemOffsets、onDraw、onDrawOver作用14. DefaultItemAnimator 原理自定义增删改动画的思路15. ItemTouchHelper 工作原理侧滑删除、拖拽排序的实现逻辑16. RecyclerView 点击 / 长按事件最佳实现方式17. ItemAnimator 各动画方法animateChange/animateRemove执行时机与视图层级操作五、滑动机制18. NestedScrollingChild2/3 嵌套滑动完整流程19. 内外层 RecyclerView 嵌套滑动事件分发拦截逻辑如何实现协同滑动20. RecyclerView 与 CoordinatorLayout/AppBarLayout 联动的 Behavior 原理21. 自定义惯性滑动fling修改摩擦系数与速度的方式22. onScrollStateChanged 三种状态切换逻辑23. 请完整描述 RecyclerView 从手指按下到滑动停止的全流程机制包括事件分发、scroll 处理、View 填充与回收、惯性滑动、嵌套滑动的整体逻辑。***24. RecyclerView 为什么滑动时不会一次性把所有 Item 布局出来它是如何做到 “边滑边布局、边滑边回收” 的***六、性能优化与内存1. 原题RecyclerView 卡顿、OOM 常见原因及优化方案2. 大数据量万级 / 10w分页加载、缓存池优化方案3. 滑动时频繁 GC 规避方案过度绘制排查4. ViewHolder/Adapter 内存泄漏场景及根治方案离屏渲染使用场景与副作用七、源码级细节1. RecyclerView 绘制流程dispatchDraw与 ItemView 绘制顺序2. GapWorker 机制在预取与异步布局中的作用3. tryGetViewHolderForPosition 方法完整执行逻辑4. “scrap” 与 “recycle” 核心概念理解5. 粘性头部Sticky Header实现思路八. 补充题目1. RecyclerView 的核心组件有哪些各自如何协作2. setHasFixedSize(true) 何时用3. Paging 3 如何接入 RecyclerView4. ItemTouchHelper 拖拽排序5. 关于PagingDataAdapter6. 快速连续 submitList旧结果会覆盖新列表吗7. 返回页面或刷新后滚动位置为什么丢失8. 补充Paging3的getRefreshKeyAndroid 高级工程师RecyclerView 高频 20 问从数据更新到复用与性能排查【Android 源码】RecylerView的深入理解一、基础原理与复用缓存1. RecyclerView 与 ListView 的核心区别是什么架构解耦RecyclerView将布局LayoutManager、复用Recycler、动画ItemAnimator、分割线ItemDecoration模块化ListView高度耦合。缓存机制RecyclerView采用四级缓存mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPoolListView仅两级缓存。布局能力RecyclerView 支持线性、网格、瀑布流及自定义布局ListView 仅支持线性布局。刷新机制RecyclerView 支持 DiffUtil 局部精准刷新ListView 仅支持全局notifyDataSetChanged。嵌套滑动RecyclerView 实现NestedScrolling 接口支持嵌套滑动ListView 嵌套易卡顿。快速记忆解耦强、缓存多、布局全、刷新准、嵌套顺。2. 四级缓存mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool各自作用、优先级与降级策略不同滑动 / 刷新场景的命中逻辑优先级mAttachedScrap mCachedViews mViewCacheExtension mRecyclerPoolmAttachedScrap/mChangedScrap屏幕内缓存存储屏幕内 detach 的 View保留完整状态布局重构时直接复用无需 rebind。单次 onLayoutChildren 结束自动清空。mCachedViews屏外缓存缓存刚滑出屏幕的 ViewHolder默认 2 个保留状态回滑时优先命中无需rebind。销毁时机被复用 / 队列满下沉 / 全局刷新 / 页面销毁mViewCacheExtension自定义缓存开发者扩展的中间层缓存优先级高于复用池。mRecyclerPool复用池按 ViewType 分组缓存清空 View 状态复用需重新 bind支持跨 Adapter 复用。销毁时机手动 clear / RecyclerView 销毁场景快速滑动优先命中 Pool回滑优先命中 Cache布局刷新优先命中 Scrap。快速记忆屏内 Scrap → 近屏 Cache → 自定义 → 复用池越靠前复用成本越低。3. mAttachedScrap 与 mCachedViews 的本质区别为何 detach 而非 removemAttachedScrap存储屏幕内可见 View通过 detach 临时分离用于布局重构如旋转、局部刷新视图层级保留。mCachedViews存储刚滑出屏幕的 View完整保留 View 状态用于快速回滑复用。detach vs removedetach 仅临时脱离父容器保留视图属性与状态remove 完全移除视图需重新 addView 重建快速记忆Scrap 管屏内、Cache 管屏外detach 暂离、remove 销毁。4. ViewHolder 定义、复用触发条件、创建时机放入 RecycledViewPool 的条件如何自定义复用池大小与策略定义ViewHolder 是一种用于优化列表项如 ListView 或RecyclerView性能的设计模式。它的核心思想是将视图的引用缓存起来避免每次 getView() 调用时都去查找视图控件即减少 findViewById() 的调用次数复用条件ViewType 一致、position 匹配、缓存命中。创建时机各级缓存均未命中时通过 Adapter.onCreateViewHolder 创建。入池条件滑出屏幕、CachedViews 已满、非固定位置 View。自定义复用池大小与策略通过 setRecycledViewPool () 设置自定义池setMaxRecycledViews (viewType, max) 配置单类型容量。快速记忆同类型复用无缓存创建Cache 满入池可自定义容量。5.onBindViewHolder 重复调用的原因及优化方案原因数据刷新、布局重测、复用池重建、焦点变更、嵌套滑动冲突。优化使用 payload 实现局部刷新开启 setHasFixedSize (true) 减少重测避免 Item 布局动态变更降低notify 调用频率。快速记忆刷新 / 布局 / 复用导致payload 固定尺寸 少通知。6. 预取Prefetch机制原理、LinearLayoutManager 预取距离 / 数量计算逻辑原理通过GapWorker 异步线程在滑动时提前加载下一屏 Item降低滑动卡顿。计算LinearLayoutManager 根据滑动速度、屏幕剩余空间计算预取距离默认一屏预取数量 当前可见 Item 数 预取 Item 数快速记忆GapWorker 异步预取按速度 空间取一屏。7. mAttachedScrap和mChangedScrap的区别在 RecyclerView 中mAttachedScrap和mChangedScrap都属于屏幕内缓存。mAttachedScrap缓存的是屏幕内位置发生改变但数据未发生变化的ViewHolder 。mChangedScrap用于缓存数据已改变的 ViewHolder二、LayoutManager 布局1. LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager 的布局逻辑差异LinearLayoutManager线性排列单行或单列布局方向可控。GridLayoutManager网格布局均分 Span 宽度 / 高度支持跨行跨列。StaggeredGridLayoutManager瀑布流布局Item 高度 / 宽度不定自动填充空白无均分规则。快速记忆Linear 线、Grid 格、Staggered 流。2. onLayoutChildren 完整执行流程锚点定位、填充、回收自定义 LayoutManager 如何处理异常布局流程确定布局锚点锚 View 或锚位置清空 Scrap 与缓存向上下 / 左右填充可见区域回收超出屏幕的 View调整边界偏移。异常处理处理边界越界、数据为空、锚点失效等场景避免布局崩溃快速记忆定锚→清缓存→填充→回收→调偏移。5. 自定义 LayoutManager 核心方法measureChild、layoutDecorated、scrollVerticallyBy/scrollHorizontallyBy作用dx/dy 如何正确消费measureChild测量子 View 尺寸。layoutDecorated布局子 View包含分割线偏移。scrollBy处理滑动偏移返回实际消费的 dx/dy。dx/dy 消费表示横向/纵向滑动的距离水平/垂直方向 。根据滑动方向与边界限制计算可滑动距离返回实际滚动值。快速记忆测尺寸、布视图、滑偏移返回实际滚动量。6. GridLayoutManager Span 分配机制动态 SpanSize 布局冲突解决方案通过setSpanSizeLookup() 自定义每个 Item 所占 Span 数量动态变更 Span 时需调用 notify 触发重布局避免布局错位处理边界 Span 分配防止越界。快速记忆SpanLookup 定占比动态改需重布局。7. 实现多布局的思路无限循环 LayoutManager 需规避的边界问题多布局通过getItemViewType区分类型对应多 ViewHolder。无限循环getItemCount 返回极大值position 取模映射规避滑动卡顿、边界闪烁、焦点错乱问题。快速记忆ViewType 分类型取模做循环。三、Adapter 与数据刷新8. notifyDataSetChanged、notifyItemChanged、notifyItemRangeChanged 的区别与性能影响notifyDataSetChanged全局刷新所有 Item 重建 rebind性能最差。notifyItemChanged单 Item 刷新支持 payload 局部刷新性能中等。notifyItemRangeChanged批量局部刷新性能最优。快速记忆全局最差、单条中等、批量最优。9. DiffUtil 核心算法Myers原理、时间 / 空间复杂度自定义 DiffUtil.Callback 方式原理基于 Eugene W. Myers 差分算法计算新旧数据集最小差异集合增删改移。复杂度O (ND)N 为数据量D为差异数。自定义继承 DiffUtil.Callback实现getOldListSize、getNewListSize、areItemsTheSame、areContentsTheSame、getChangePayload。快速记忆差分找最小差异O (ND)五步回调自定义。10.AsyncListDiffer 异步计算逻辑、线程池策略如何避免主线程阻塞在后台线程执行 Diff 计算计算完成后主线程应用更新结果使用独立线程池避免阻塞通过锁保证数据一致性。快速记忆后台算、主线更线程池防阻塞。11. payload 精准局部刷新原理在 Android 中RecyclerView 的 局部刷新是通过 notifyItemRangeChanged(intpositionStart, int itemCount, Object payload) 实现的。其核心原理是 利用 payload参数传递差异信息只刷新 item 中需要更新的部分 UI而不是整个 item。12. notifyItemMoved 底层实现为何移动操作会导致其他 Item 重复 bind移动操作改变相邻 Item 位置触发位置校验与 rebind优化减少移动范围使用 DiffUtil 批量处理移动。快速记忆移动改位置→相邻重绑Diff 批量优化。13. RecylerView实现局部刷新的原理RecyclerView 实现局部刷新主要依赖于精准的数据集变化计算以及对应的视图更新机制DiffUtil 算法确认数据集变化生成DiffResult通知 RecyclerView 更新将DiffResult中的变化信息传递给 RecyclerView。notifyItemX(position) 或者 notifyItemChanged(int position, Nullable Object payload)用于通知指定位置的 item 发生了变化并且可以携带“payload”信息。四、分割线、动画与交互13. 自定义 ItemDecoration 核心方法getItemOffsets、onDraw、onDrawOver作用getItemOffsets设置 Item 四周间距占用布局空间。onDraw在 ItemView 下层绘制如分割线。onDrawOver在 ItemView 上层绘制如角标、遮罩。快速记忆Offsets 占空、Draw 下层、Over 上层。14. DefaultItemAnimator 原理自定义增删改动画的思路原理默认处理 Item 增删改移的过渡动画自定义继承 SimpleItemAnimator重写animateAdd、animateRemove、animateChange、animateMove。快速记忆四动画增删改移重写方法自定义。15. ItemTouchHelper 工作原理侧滑删除、拖拽排序的实现逻辑监听滑动 / 拖拽手势回调 onSwiped侧滑、onMove拖拽实时更新 ViewHolder 偏移同步修改数据源。快速记忆侧滑删、拖拽移回调改数据。16. RecyclerView 点击 / 长按事件最佳实现方式在 ViewHolder 中绑定点击事件避免重复设置通过接口回调解耦 Adapter 与业务层。17. ItemAnimator 各动画方法animateChange/animateRemove执行时机与视图层级操作animateChangeItem 内容变更时执行处理新旧视图过渡。animateRemoveItem 移除时执行处理视图退场动画。层级在 dispatchDraw 阶段执行动画不阻塞布局流程。快速记忆改时 Change、删时 Remove绘制阶段执行。五、滑动机制18. NestedScrollingChild2/3 嵌套滑动完整流程子 View 发起滑动 → 父 View 预拦截 → 父子协同消费滑动距离 → 惯性滑动联动Child3 支持链式传递。快速记忆子发→父拦→协同消费。19. 内外层 RecyclerView 嵌套滑动事件分发拦截逻辑如何实现协同滑动按方向分流父层拦截一个方向子层处理另一方向通过requestDisallowInterceptTouchEvent控制父层拦截。快速记忆分方向拦截禁止父拦截。20. RecyclerView 与 CoordinatorLayout/AppBarLayout 联动的 Behavior 原理Behavior监听嵌套滑动根据偏移量动态调整关联 View如折叠 AppBar重写onNestedScroll处理联动逻辑。快速记忆监听滑动联动偏移。21. 自定义惯性滑动fling修改摩擦系数与速度的方式重写 fling () 方法修改 VelocityTracker 速度、ViewConfiguration 摩擦系数控制惯性滑动距离。快速记忆改速度 摩擦控惯性。22. onScrollStateChanged 三种状态切换逻辑IDLE静止状态。DRAGGING手指触摸拖动。SETTLING手指离开后的惯性滑动。切换触摸→DRAGGING松开→SETTLING停止→IDLE。快速记忆静、拖、滑。23. 请完整描述 RecyclerView 从手指按下到滑动停止的全流程机制包括事件分发、scroll 处理、View 填充与回收、惯性滑动、嵌套滑动的整体逻辑。***事件分发触摸事件经由 onInterceptTouchEvent 判断是否拦截按下时记录起点坐标移动时判定为滑动意图后开始消费事件。手指拖动计算偏移 dy/dx → 通过 scrollByInternal 消费距离 → 触发LayoutManager 的 scrollVerticallyBy/scrollHorizontallyBy → 调用 fill()方法填充新可见区域、回收滑出屏幕的 Item。填充与回收逻辑滑动时先从缓存获取 ViewHolder填充到新位置超出屏幕的 View 按优先级存入 CachedViews 或RecycledViewPool。惯性滑动手指抬起时通过 VelocityTracker 获取滑动速度 → 交给 OverScroller 计算减速轨迹 → 通过 computeScroll() 持续回调更新偏移 → 同步执行填充与回收。嵌套滑动支持遵循 NestedScrollingChild2/3 机制滑动前先询问父 View 是否消费部分距离实现协同滑动如与AppBarLayout 联动。滑动停止 惯性速度衰减为 0 或手动打断滑动时状态切换为 IDLE完成一次完整滑动流程。快速记忆事件拦截 → 计算偏移 → 填充回收 → 惯性滚动 → 嵌套协同 → 停止 idle。24. RecyclerView 为什么滑动时不会一次性把所有 Item 布局出来它是如何做到 “边滑边布局、边滑边回收” 的***RecyclerView 不会全量布局而是采用可见区域驱动的增量布局只在onLayoutChildren 和滑动时布局当前屏幕可见范围的 Item。滑动过程中通过fill() 方法动态向滑动方向填充即将显示的 Item同时回收反方向超出屏幕的 Item。配合四级缓存实现 ViewHolder 复用避免频繁创建销毁 View。结合预取机制提前加载下一屏 Item保证滑动流畅。快速记忆只布局可见区域滑动填充 回收缓存复用预取兜底。六、性能优化与内存1. 原题RecyclerView 卡顿、OOM 常见原因及优化方案卡顿onBind 耗时、布局复杂、过度绘制、频繁 GC。OOM图片过大、复用池溢出、内存泄漏。优化异步加载、简化布局、减少对象创建、复用池调优、图片压缩。快速记忆耗时 / 复杂 / 泄漏→卡顿 OOM异步 简化 复用。2. 大数据量万级 / 10w分页加载、缓存池优化方案分页加载 DiffUtil 局部刷新扩容复用池图片三级缓存避免动态布局。快速记忆分页 差分 大复用池 图缓存。3. 滑动时频繁 GC 规避方案过度绘制排查GC避免 onBind 创建对象使用对象池。过度绘制减少重复背景、使用 clipRect、精简 onDrawForeground 逻辑。快速记忆少创建防 GC少背景防过度绘。4. ViewHolder/Adapter 内存泄漏场景及根治方案离屏渲染使用场景与副作用泄漏ViewHolder 持有 Context、Adapter 匿名内部类 → 弱引用、静态内部类。离屏渲染setLayerType 开启用于复杂动画副作用占用显存低机型卡顿。快速记忆弱引用防泄漏离屏渲染慎开。七、源码级细节1. RecyclerView 绘制流程dispatchDraw与 ItemView 绘制顺序drawBackground → dispatchDraw绘制子 View→ drawForeground → 绘制ItemDecoration。快速记忆背景→子项→前景→分割线。2. GapWorker 机制在预取与异步布局中的作用异步线程执行预取、布局计算分担主线程压力提升滑动流畅度。快速记忆异步干活主线减负。3. tryGetViewHolderForPosition 方法完整执行逻辑查找 Scrap → 查找 Cache → 查找 Extension → 查找 Pool → 未命中则创建 → 绑定数据。快速记忆逐级查缓存无则新建。4. “scrap” 与 “recycle” 核心概念理解scrap临时 detach保留状态快速复用recycle完全回收清空状态进入复用池快速记忆scrap 暂存recycle 清空。5. 粘性头部Sticky Header实现思路通过 ItemDecoration.onDrawOver 在顶层绘制固定头部监听滑动动态更新头部内容与位置。快速记忆Decoration 上层画滑动更内容。八. 补充题目1. RecyclerView 的核心组件有哪些各自如何协作RecyclerView 将数据绑定、布局、装饰和动画拆分为不同职责Adapter提供条目数量、类型并创建和绑定 ViewHolderViewHolder保存条目视图引用LayoutManager负责条目的测量、布局与滚动ItemDecoration提供间距和装饰绘制ItemAnimator处理条目更新动画。RecyclerView 协调这些组件并通过 Recycler 管理 ViewHolder 的获取与复用支持多类型、动态更新及复杂排布的列表。为什么要将布局交给 LayoutManager将布局与数据绑定分开同一套条目绑定逻辑可配合线性、网格等布局策略切换时仍需验证条目尺寸、跨度和滚动状态。使用 RecyclerView 就能保证列表流畅吗2. setHasFixedSize(true) 何时用一句话告诉 RecyclerView列表整体尺寸不会随着 item 内容变化而改变帮 RecyclerView 跳过重复测量提升性能。✅ 适合RecyclerView 写死宽高match_parent、固定 dpitem 增删不会改变 RV 容器大小。比如全屏列表RV 占满屏幕item 再多 RV 的大小不变就可以打开 true。NestedScrollView 包 RV 能设吗不能严禁设置 true必须 false。原因NestedScrollView 的高度本身是wrap_content特性它要测量全部子 View 的总高度。RV 放在里面RV 的整体高度取决于 item 的总高度item 数量变化RV 的总高度就会变化。setHasFixedSize(true)的含义就是告诉 RV你的容器总高度固定不变但这里 RV 高度是动态变化的和这个前提矛盾。如果强行写 true会出现测量异常列表显示不全、空白、item 不渲染。结论NestedScrollView 包裹 RV →setHasFixedSize(false)和 wrap_content 冲突setHasFixedSize(true)要求 RecyclerView 本身不是 wrap_content。当 RV 布局宽高是match_parent或者固定 dpRV 容器尺寸固定才可以true当 RV 高度是wrap_contentRV 整体高度会随 item 变化不能开启 true3. Paging 3 如何接入 RecyclerViewPaging3 接入 RecyclerView核心是使用PagingDataAdapter它继承 RecyclerView.Adapter内置 DiffUtil专门接收 PagingData。整体分 4 步定义 PagingDataAdapter继承PagingDataAdapterT, VH传入 DiffUtil.ItemCallback用来做 item 差异比对实现增量更新。和普通 RV Adapter 写法接近只需要实现 onCreateViewHolder、onBindViewHolder内部用getItem(position)拿数据。ViewModel 中构建 Pager生成 FlowPagingData通过 Pager 配置分页参数、PagingSource有离线缓存场景就加上 RemoteMediator最后.cachedIn(viewModelScope)缓存数据流屏幕旋转不用重新加载。Activity/Fragment 里订阅 Flow提交 PagingData 给 Adapter用lifecycleScopecollectLatest订阅分页 Flow拿到 PagingData 后调用adapter.submitData(pagingData)。PagingDataAdapter 内部自动处理分页数据合并、Diff 增量刷新不用自己维护列表集合。绑定 RecyclerViewrv.adapter adapter设置 LayoutManager。还可以监听adapter.loadStateFlow处理加载中、失败、空态、重试逻辑也能用withLoadStateFooter添加底部加载 / 错误 Footer。4. ItemTouchHelper 拖拽排序ItemTouchHelper 通过 onMove/onSwiped 提供拖拽和侧滑回调。拖拽时必须先更新 Adapter 实际读取的数据顺序再发出对应移动通知确保数据与界面一致。对普通 Adapter可维护独立的可变工作列表并 notifyItemMoved对 ListAdapter不得修改 currentList 或共享的旧对象且不能只手工通知移动却保留旧数据。如果每次移动都 submitList新顺序会异步应用必须考虑拖拽事件与提交结果的时序。需要即时反馈时可在拖拽期间使用明确管理工作列表的 Adapter结束后提交不可变快照并持久化排序同一次更新不能再重复发 notify 与 Diff 通知。拖拽与 diff 冲突冲突根源拖拽时手动修改内存数据源DiffUtil 在后台异步对比新旧数据快照状态不一致引发闪烁、位置错乱。解决方案拖拽过程只保留 ItemTouchHelper 自带的 UI 视觉动画不修改数据源、不手动 notify。拖拽松手完成后生成一份更新后的完整数据集调用 submitList 提交给 Adapter由 DiffUtil 统一计算差异刷新。拖拽期间收到服务端新列表怎么办优先做状态互斥拖拽进行中暂存服务端返回的新数据不直接提交给 Adapter等拖拽手势结束、松手完成之后再把缓存的新列表执行 submitList 刷新。5. 关于PagingDataAdapter普通 Adapter 需要自己维护 List、手动 notifyListAdapter 自带 Diff提交完整列表做局部刷新但一次性载入所有数据。PagingDataAdapter 是 ListAdapter 的子类基于 PagingData 实现按需预加载、自动释放远端页内存自带分页状态回调适合大数据分页场景。6. 快速连续 submitList旧结果会覆盖新列表吗快速连续调用submitList旧的 Diff 任务会被直接丢弃最终只会生效最后一次提交的新列表不会出现旧结果覆盖新列表。底层是AsyncListDiffer的版本号机制每次 submitList 都会递增 generation 版本标记。如果上一次 Diff 还在后台计算这时又提交新列表旧 Diff 任务完成后会判断版本号过期直接放弃应用结果只执行最新一次提交的 Diff 结果。7. 返回页面或刷新后滚动位置为什么丢失滚动位置丢失本质RecyclerView 的 LayoutManager 保存滚动位置依赖当前内存里的数据集数据集被完全替换、Adapter 重建或者页面重建时旧的位置锚点找不到对应的 item滚动位置就丢了。普通 ListAdapter submitList 全量刷新调用 submitList 提交全新列表旧数据集直接替换。LayoutManager 记录的 position 对应的旧 item 不存在了滚动位置丢失。注意如果只是列表局部变更增删少量 itemDiff 能维持位置全量替换数据集最容易丢位置。PagingData 场景PagingDataAdapter 重点Pager 重新创建、PagingSource 刷新下拉刷新旧 PagingData 失效内存中已加载的页面被清空。LayoutManager 找不到之前的锚点数据滚动位置丢失。Paging3 提供getRefreshKey用来在刷新时计算锚点恢复滚动位置这就是它的作用。页面重建屏幕旋转、配置变更默认 ViewModel 能保存数据但如果没有用cachedIn(viewModelScope)分页 Flow 会重建重新加载数据RV 状态丢失或者没保存 LayoutManager 的状态。普通 List不要频繁全量 submitList需要保存位置时在刷新前取出 LayoutManager 的onSaveInstanceState刷新完成后恢复。Paging3正确实现 PagingSource 的 getRefreshKey用来计算锚点位置下拉刷新后恢复滚动位置同时分页 Flow 要加.cachedIn(viewModelScope)配置变更不复加载。8. 补充Paging3的getRefreshKeygetRefreshKey是 PagingSource 的锚点计算方法下拉刷新、页面重新加载的时候Paging3 调用它根据当前屏幕正在显示的条目算出刷新后要加载的页码用来恢复滚动位置。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑