You need to enable JavaScript to run this app. SearchView过滤RecyclerView 点击位置错位、数据不匹配
优惠活动
大模型
产品
解决方案
定价
更多

SearchView过滤RecyclerView 点击位置错位、数据不匹配

问题核心根源
  • 数据来源错位:Adapter过滤后内部维护的是临时的过滤结果列表,但MainActivity处理点击事件时,直接从自身持有的原始全量列表mCategories中按position取数据,两个列表的元素、索引完全不对应。

    举个实际复现场景:原始列表为[分类A, 分类B, 分类C, 分类D],搜索关键词“分类B”后,Adapter实际展示的列表为[分类B]。此时用户点击这个展示的条目(Adapter返回的位置是0),原代码会从全量列表取位置0的元素,也就是分类A,和用户实际看到的点击项完全不符,这就是错位的直接表现。

  • 过滤实现不规范:performFiltering运行在子线程,原代码直接在子线程修改Adapter的主线程成员变量mCategorie,容易引发并发导致的列表异常、数据错乱。
  • 初始化逻辑冗余:MainActivity在解析JSON的循环内每加一个条目就重新创建一次Adapter,不仅造成性能浪费,也容易导致Adapter持有不同步的列表引用。
具体修复步骤

1. 修正点击事件的数据获取逻辑

Adapter已经封装了getItem(int position)方法,该方法从Adapter当前正在展示的列表(不管是过滤后还是原始列表)中取对应位置的数据,直接替换MainActivity中原先从全量列表取数据的逻辑:

@Override
public void onItemClick(View view, int position) {
    Intent intent = new Intent(MainActivity.this, TagsActivity.class);
    // 从Adapter当前维护的展示列表中获取被点击的实体,而非直接读原全量列表
    Categorie clickedItem = (Categorie) adapter.getItem(position);
    intent.putExtra("id_cat", clickedItem.getId());
    intent.putExtra("title", clickedItem.getName());
    startActivityForResult(intent, 1);
}

2. 优化Filter实现,避免子线程修改UI成员

原代码在performFiltering的子线程中直接给Adapter的mCategorie赋值,存在并发风险。调整为子线程只操作本地变量,所有列表更新逻辑放到主线程的publishResults方法中执行:

private Filter exampleFilter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        // 子线程内创建独立的过滤结果列表,不修改Adapter全局成员
        List<Categorie> filteredResult = new ArrayList<>();
        String filterKeyword = constraint.toString().toLowerCase().trim();

        if (filterKeyword.isEmpty()) {
            filteredResult.addAll(mCategoriefull);
        } else {
            for (Categorie item : mCategoriefull) {
                if (item.getName().toLowerCase().contains(filterKeyword)) {
                    filteredResult.add(item);
                }
            }
        }

        FilterResults results = new FilterResults();
        results.values = filteredResult;
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        // 主线程内更新Adapter的展示列表,刷新UI
        mCategorie = (List<Categorie>) results.values;
        notifyDataSetChanged();
    }
};

3. 修正Adapter的列表拷贝逻辑,避免引用错乱

原Adapter构造函数直接把传入的列表引用赋值给全量备份mCategoriefull,如果外部修改原列表,会直接导致过滤源被篡改。调整为对列表做一次拷贝:

public CategorieAdapter(Context mContext, List<Categorie> mCategorie) {
    this.mContext = mContext;
    // 展示列表独立拷贝,避免外部引用变更影响Adapter内部状态
    this.mCategorie = new ArrayList<>(mCategorie);
    // 全量备份列表独立拷贝,保证过滤操作的数据源稳定
    this.mCategoriefull = new ArrayList<>(mCategorie);
    this.mInflater = LayoutInflater.from(mContext);
}

4. 优化MainActivity的数据加载逻辑

原代码在JSON解析的循环内反复创建Adapter、绑定RecyclerView,调整为等所有数据加载完成后,一次性初始化Adapter:

@Override
public void onResponse(String response) {
    try {
        JSONArray jsonArray = new JSONArray(response);
        mCategories.clear(); // 清空原有缓存,避免重复加载
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            int id = Integer.parseInt(object.getString("id_cat"));
            String name = object.getString("name");
            mCategories.add(new Categorie(id, name));
        }
        // 全部数据解析完成后,再初始化并绑定Adapter
        adapter = new CategorieAdapter(MainActivity.this, mCategories);
        categoriesListView.setAdapter(adapter);
        adapter.setClickListener(this);
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 09:06:09