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

自定义Adapter实现Filter的ListView触发IndexOutOfBoundsException问题

解决ListView搜索过滤异常的问题

嘿,我看你遇到了自定义ListView搜索过滤失效的问题,结合你给出的代码片段,大概率是Filter实现里的数据处理逻辑踩了坑——毕竟用ArrayAdapter做过滤时,很容易因为没区分「原始完整数据集」和「过滤后数据集」导致异常,咱们一步步来修复:

首先,排查核心问题

你当前的Adapter里可能只维护了一个warrantyList,过滤操作直接修改了这个列表,导致后续无法恢复原始数据,或者过滤逻辑没有正确更新UI展示的数据。这是新手实现Filter最常见的错误。

正确的Adapter实现方案

我们需要在Adapter中维护两个数据集:

  • 一个保存从数据库获取的完整原始数据(用于过滤时的匹配源)
  • 一个保存当前要展示的过滤后数据(用于ListView的显示)

下面是完整的修正版Adapter代码:

public class WarrantyAdapter extends ArrayAdapter<ServicesWarranty> implements Filterable {
    // 原始完整数据集,过滤时的匹配源
    private ArrayList<ServicesWarranty> originalWarranties;
    // 过滤后要展示的数据集
    private ArrayList<ServicesWarranty> filteredWarranties;
    private Context context;

    public WarrantyAdapter(Context context, ArrayList<ServicesWarranty> warranties) {
        super(context, 0, warranties);
        this.context = context;
        // 初始化原始数据集(做深拷贝,避免引用传递导致原始数据被修改)
        this.originalWarranties = new ArrayList<>(warranties);
        this.filteredWarranties = new ArrayList<>(warranties);
    }

    @Override
    public int getCount() {
        // 返回过滤后数据集的数量
        return filteredWarranties.size();
    }

    @Override
    public ServicesWarranty getItem(int position) {
        // 返回过滤后数据集对应位置的项
        return filteredWarranties.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 这里是你原本的getView实现,注意用filteredWarranties.get(position)获取数据
        ServicesWarranty warranty = filteredWarranties.get(position);
        // ... 你的视图绑定逻辑(比如填充文本、图片等)
        return convertView;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                ArrayList<ServicesWarranty> tempFilteredList = new ArrayList<>();

                // 如果搜索关键词为空,直接返回原始数据集
                if (constraint == null || constraint.length() == 0) {
                    tempFilteredList.addAll(originalWarranties);
                } else {
                    String filterPattern = constraint.toString().toLowerCase().trim();
                    // 遍历原始数据集,匹配关键词
                    for (ServicesWarranty item : originalWarranties) {
                        // 替换成你实际要匹配的字段,比如item.getWarrantyNo()、item.getCustomerName()等
                        if (item.getTargetField().toLowerCase().contains(filterPattern)) {
                            tempFilteredList.add(item);
                        }
                    }
                }

                results.values = tempFilteredList;
                results.count = tempFilteredList.size();
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // 更新过滤后数据集,并通知ListView刷新
                filteredWarranties.clear();
                filteredWarranties.addAll((ArrayList<ServicesWarranty>) results.values);
                notifyDataSetChanged();
            }
        };
    }
}

然后修正你的listShow方法

确保初始化Adapter时传入完整的数据集,并且不需要每次过滤都重新初始化Adapter:

private void listShow() {
    warranties = db.getAllServWarr();
    // 初始化Adapter时传入完整的原始数据
    adapter = new WarrantyAdapter(serviceswarranty_activity.this, warranties);
    listView.setAdapter(adapter);
}

最后,搜索触发的逻辑示例

比如你在搜索框的文本变化监听里调用过滤:

searchEditText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // 调用Adapter的过滤方法
        adapter.getFilter().filter(s);
    }

    @Override
    public void afterTextChanged(Editable s) {}
});

关键注意点

  • 深拷贝数据集:初始化originalWarranties时要用new ArrayList<>(warranties),避免和传入的列表共用同一个引用,导致原始数据被意外修改。
  • 过滤逻辑要匹配实际字段:把item.getTargetField()替换成你实际要搜索的字段(比如保修单号、客户名称等)。
  • performFiltering是后台线程:不要在这个方法里操作UI,所有UI更新都要放在publishResults里。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:21:47