You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多Activity场景下RecyclerView出现java.lang.IndexOutOfBoundsException崩溃问题求助

解决RecyclerView GapWorker预取导致的IndexOutOfBoundsException

这个崩溃是RecyclerView的**后台预取机制(GapWorker)**和主线程数据源更新之间的竞态条件导致的——哪怕你所有操作都在主线程,也可能因为预取线程的延迟执行,拿到不一致的数据源状态而触发索引越界。这也是为什么你本地测试很难复现,它属于偶发的边缘场景,只有特定条件下才会触发。

下面是具体的解决方案,按优先级排序:

1. 升级RecyclerView版本(最推荐)

你当前使用的1.2.1版本存在不少预取相关的已知bug,官方在1.3.0及以上版本中修复了这类GapWorker的竞态问题。修改你的Gradle依赖:

implementation 'androidx.recyclerview:recyclerview:1.3.0' // 或更高稳定版本,比如最新的1.4.0

2. 确保数据源的线程安全性与notify方法正确性

  • 改用线程安全的数据源容器:比如用CopyOnWriteArrayList替代普通ArrayList,这样预取线程看到的数据源始终是一致的快照,不会出现中间状态的索引越界。
  • 严格遵循RecyclerView的notify规范:修改数据源后必须立刻调用对应的notify方法,比如添加单条数据用notifyItemInserted(position),批量添加用notifyItemRangeInserted(start, count),禁止只修改数据源而不通知RecyclerView,否则预取线程会基于旧的数据集大小尝试获取ViewHolder。

3. 临时禁用预取机制(仅作为应急方案)

如果暂时无法升级版本,可以关闭预取来规避问题,但这会影响滚动流畅度,不推荐长期使用:

方法一:设置ItemViewCacheSize为0

recyclerView.setItemViewCacheSize(0);

方法二:自定义LayoutManager禁用预取

public class NoPrefetchLinearLayoutManager extends LinearLayoutManager {
    @Override
    public boolean isItemPrefetchEnabled() {
        return false;
    }
}

然后给RecyclerView设置这个自定义LayoutManager即可。

为什么本地测试没复现?

GapWorker的预取触发条件和系统资源、滚动行为强相关:只有当RecyclerView判断需要预取(比如快速滚动、系统空闲时)才会启动后台线程。本地测试很难覆盖所有极端场景,比如快速滚动后立刻修改数据源、系统CPU负载高导致预取线程延迟执行等,所以控制台会上报但你复现不了。

内容的提问来源于stack exchange,提问作者Muhammad Riaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 02:52:33