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

Android RecyclerView点击CardView触发数组越界异常问题排查与修复

RecyclerView条目点击返回后快速点击导致数组越界崩溃

问题描述

我开发的Android应用中,RecyclerView的每个条目是CardView,点击时会根据其在RecyclerView中的位置加载对应的DetailsActivity。近期发现从详情页返回列表界面后快速点击CardView,应用会因ArrayIndexOutOfBoundsException崩溃,推测是异步相关问题,希望了解修复方法。

相关代码

条目获取代码(CardsAdapter.java)

public List<Card> mListItems;
...

public Card getItem(int position) {   
    return mListItems.get(position);  // line 102
}

点击事件处理代码(CardsAdapter.java)

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View itemView = layoutInflater.inflate(R.layout.item_todo, parent,false);
    final ItemHolder itemHolder = new ItemHolder(itemView);   

    itemHolder.cardView.setOnClickListener(view -> {

        Card adapterItem = CardsAdapter.this.getItem(itemHolder.getBindingAdapterPosition()); // line 639
        int adapPos = itemHolder.getBindingAdapterPosition();
        if (adapPos == RecyclerView.NO_POSITION || recyclerItemClickListener == null) {
            return;
        }
        recyclerItemClickListener.onItemClick(itemHolder.cardView, adapterItem, adapPos);
    });
...
}

崩溃日志

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.todo.quickcards, PID: 10677
java.lang.ArrayIndexOutOfBoundsException: length=36; index=-1
at java.util.ArrayList.get(ArrayList.java:439)
at com.todo.quickcards.adapter.CardsAdapter.getItem(CardsAdapter.java:102)
at com.todo.quickcards.adapter.CardsAdapter.lambda$onCreateViewHolder$0$com-todo-quickcards-adapter-CardsAdapter(CardsAdapter.java:639)
at com.todo.quickcards.adapter.CardsAdapter$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
at android.view.View.performClick(View.java:6897)
at android.view.View$PerformClick.run(View.java:26101)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

修复方案

问题根源

点击事件中先调用getItem()获取数据,再校验位置有效性。当从详情页返回后快速点击,RecyclerView可能尚未完成视图绑定或数据更新,此时getBindingAdapterPosition()会返回RecyclerView.NO_POSITION(即-1),直接用这个无效位置去访问列表就触发了数组越界。

修复步骤

  1. 调整校验顺序:先判断位置有效性,再获取数据
    将位置校验逻辑移到获取数据之前,避免无效位置传入getItem()方法:
itemHolder.cardView.setOnClickListener(view -> {
    // 先获取位置并校验有效性
    int adapPos = itemHolder.getBindingAdapterPosition();
    if (adapPos == RecyclerView.NO_POSITION || recyclerItemClickListener == null) {
        return;
    }
    // 校验通过后再获取数据
    Card adapterItem = CardsAdapter.this.getItem(adapPos);
    recyclerItemClickListener.onItemClick(itemHolder.cardView, adapterItem, adapPos);
});
  1. 给getItem()方法增加边界校验
    为了避免其他地方调用getItem()时也出现类似崩溃,给该方法增加位置合法性判断:
public Card getItem(int position) {   
    // 校验位置是否在有效范围内
    if (position < 0 || position >= mListItems.size()) {
        return null; // 也可根据业务需求抛出自定义异常或返回默认值
    }
    return mListItems.get(position);
}

额外说明

返回列表后快速点击时,RecyclerView的视图可能处于复用或更新状态,ViewHolder的位置临时失效是正常现象。通过提前校验位置有效性,就能过滤掉这种无效的点击事件,避免崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:45:17