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),直接用这个无效位置去访问列表就触发了数组越界。
修复步骤
- 调整校验顺序:先判断位置有效性,再获取数据
将位置校验逻辑移到获取数据之前,避免无效位置传入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); });
- 给
getItem()方法增加边界校验
为了避免其他地方调用getItem()时也出现类似崩溃,给该方法增加位置合法性判断:
public Card getItem(int position) { // 校验位置是否在有效范围内 if (position < 0 || position >= mListItems.size()) { return null; // 也可根据业务需求抛出自定义异常或返回默认值 } return mListItems.get(position); }
额外说明
返回列表后快速点击时,RecyclerView的视图可能处于复用或更新状态,ViewHolder的位置临时失效是正常现象。通过提前校验位置有效性,就能过滤掉这种无效的点击事件,避免崩溃。
内容的提问来源于stack exchange,提问作者AJW
相关产品推荐
相关产品推荐

