如何在带筛选的RecyclerView中始终显示10条数据(规避索引越界)
解决RecyclerView筛选时仅显示10条数据的索引越界问题
嘿,我碰到过类似的问题,其实核心原因很简单——你应该是在筛选后不管结果有多少,都硬返回10作为getItemCount()的结果,对吧?当筛选出来的数据不足10条时,RecyclerView去访问超出结果长度的索引,自然就抛出IndexOutOfBoundsException了。结合你用Realm的场景,给你两个靠谱的实现方案:
方案一:动态计算返回的item数量
核心思路是让getItemCount()返回筛选结果数量和10的较小值,确保永远不会请求超出实际数据范围的索引:
- 在适配器中维护两个RealmResults对象:一个存原始全量数据,一个存筛选后的结果
- 实现筛选方法,根据输入更新筛选结果集
- 重写
getItemCount()时取两者的最小值 - 在绑定ViewHolder时直接从筛选结果集取数据
修改后的关键代码片段:
public class RealmAutoCompleteAdapter extends RecyclerView.Adapter<RealmAutoCompleteAdapter.ProductViewHolder> { private Realm realm; private RealmResults<FieldsItem> originalFullResults; // 原始283条全量数据 private RealmResults<FieldsItem> currentFilteredResults; // 筛选后的结果 private RealmChangeListener<RealmResults<FieldsItem>> realmChangeListener; // 构造方法初始化全量数据 public RealmAutoCompleteAdapter(Realm realm, RealmResults<FieldsItem> fullResults) { this.realm = realm; this.originalFullResults = fullResults; this.currentFilteredResults = fullResults; // 初始默认显示全量的前10条 setupRealmListener(); } // 外部调用的筛选方法(比如在TextView的TextWatcher中触发) public void performFilter(String searchQuery) { if (TextUtils.isEmpty(searchQuery)) { // 空查询时回到全量数据 currentFilteredResults = originalFullResults; } else { // 根据输入执行Realm查询,匹配你需要筛选的字段 currentFilteredResults = realm.where(FieldsItem.class) .contains("targetFieldName", searchQuery, Case.INSENSITIVE) .findAll(); } notifyDataSetChanged(); // 更新列表 } private void setupRealmListener() { // 监听原始数据变化,自动更新列表 realmChangeListener = results -> notifyDataSetChanged(); originalFullResults.addChangeListener(realmChangeListener); } @Override public int getItemCount() { // 关键:永远返回筛选结果数量和10的较小值 return Math.min(currentFilteredResults.size(), 10); } @Override public void onBindViewHolder(@NonNull ProductViewHolder holder, int position) { // 直接从筛选结果集中取数据,position不会越界 FieldsItem item = currentFilteredResults.get(position); holder.itemTextView.setText(item.getTargetField()); // 其他绑定逻辑... } // ProductViewHolder定义和其他方法省略... }
方案二:查询阶段直接限制结果数量(更高效)
既然你只需要最多10条数据,不如直接在Realm的查询语句中加上limit(10),这样筛选结果集本身最多只有10条,getItemCount()直接返回结果集的size即可,从根源避免越界:
修改筛选方法中的查询逻辑:
public void performFilter(String searchQuery) { if (TextUtils.isEmpty(searchQuery)) { currentFilteredResults = realm.where(FieldsItem.class) .limit(10) // 全量时也只取前10条 .findAll(); } else { currentFilteredResults = realm.where(FieldsItem.class) .contains("targetFieldName", searchQuery, Case.INSENSITIVE) .limit(10) // 筛选结果最多返回10条 .findAll(); } notifyDataSetChanged(); } // 此时getItemCount()可以直接返回结果集的size @Override public int getItemCount() { return currentFilteredResults.size(); }
注意事项
- 记得在适配器销毁时移除Realm的监听器,避免内存泄漏
- 如果需要支持Realm的自动数据更新,确保筛选后的结果集也能正确监听变化(方案一中的监听器已经覆盖了原始数据变化的场景)
内容的提问来源于stack exchange,提问作者SMahdiS
相关产品推荐
相关产品推荐

