Android RecyclerView分页快速点击触发fromIndex大于toIndex异常如何解决
问题根因
你虽然在setAdapter里做了按钮可见性的控制,但Android的View可见性更新不是同步生效的,用户快速点击时,按钮隐藏的逻辑还没执行,点击事件就已经触发多次,导致CURRENT_PAGE超出合法范围(小于1或者大于TOTAL_PAGE),最终计算出来的FROM大于TO,触发subList的参数非法异常。
修复方案
1. 点击事件增加边界前置校验(必改)
在修改CURRENT_PAGE之前先判断是否已经是边界值,不符合条件直接拦截点击事件,这是最核心的修复:
butNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 前置校验:已经是最后一页直接拦截 if (CURRENT_PAGE >= TOTAL_PAGE) { return; } CURRENT_PAGE = CURRENT_PAGE+1; FROM = (CURRENT_PAGE-1)* Constant.ITEM_PER_PAGE; TO = FROM + Constant.ITEM_PER_PAGE; if(TO>TOTAL){ TO = TOTAL; } setAdapter(FROM,TO); } }); butPrev.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 前置校验:已经是第一页直接拦截 if (CURRENT_PAGE <= 1) { return; } CURRENT_PAGE = CURRENT_PAGE-1; FROM = (CURRENT_PAGE-1) * Constant.ITEM_PER_PAGE; TO = FROM + Constant.ITEM_PER_PAGE; if(TO>TOTAL){ TO = TOTAL; } setAdapter(FROM,TO); } });
2. 增加subList参数兜底校验
在调用subList之前先对参数做合法性校验,避免其他异常场景也触发崩溃:
private void setAdapter(int From, int To) { textPageCount.setText(CURRENT_PAGE +"/" +TOTAL_PAGE); butPrev.setVisibility((CURRENT_PAGE ==1) ? View.INVISIBLE : View.VISIBLE); butNext.setVisibility((CURRENT_PAGE == TOTAL_PAGE) ? View.INVISIBLE : View.VISIBLE); progressBar.setVisibility(View.GONE); // 兜底参数校验 int listSize = Constant.arrayListCategories.size(); From = Math.max(From, 0); To = Math.min(To, listSize); if (From >= To) { // 参数非法直接返回,避免崩溃 setEmpty(); return; } ArrayList<ItemCategory> arraylistsub = new ArrayList<>(Constant.arrayListCategories.subList(From, To)); adapterCat = new AdapterCat(arraylistsub); recyclerView.setAdapter(adapterCat); setEmpty(); }
可选优化:增加点击防抖
如果要彻底避免快速点击的问题,可以给按钮加500ms防抖逻辑,短时间内只响应一次点击:
// 类中增加变量记录上次点击时间 private long lastClickTime = 0; // 点击事件中增加防抖判断 butNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { long currentTime = System.currentTimeMillis(); if (currentTime - lastClickTime < 500) { return; } lastClickTime = currentTime; // 原有逻辑 if (CURRENT_PAGE >= TOTAL_PAGE) { return; } CURRENT_PAGE = CURRENT_PAGE+1; FROM = (CURRENT_PAGE-1)* Constant.ITEM_PER_PAGE; TO = FROM + Constant.ITEM_PER_PAGE; if(TO>TOTAL){ TO = TOTAL; } setAdapter(FROM,TO); } });
性能优化建议
当前每次分页都重新创建Adapter、重新绑定RecyclerView的性能损耗较大,建议复用同一个Adapter,仅更新Adapter内部的数据集后调用notifyDataSetChanged即可,分页切换的流畅度会明显提升。
内容的提问来源于stack exchange,提问作者Nidhi
相关产品推荐
相关产品推荐

