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

RecyclerView搜索过滤时notifyDataSetChanged失效问题求助

解决SearchView过滤RecyclerView时notifyDataSetChanged失效的问题

嗨,我看了你的代码,问题其实很明显——你在Adapter里维护了好几个列表,但RecyclerView实际绑定的列表和你在setFilter里更新的根本不是同一个!

先给你捋清楚:

  • 你的onBindViewHolder里用的是eventListFiltered.get(position),getItemCount返回的也是eventListFiltered.size(),说明RecyclerView显示的是eventListFiltered这个列表的数据。
  • 但你的setFilter方法里操作的是filteredList,这个列表从来没和RecyclerView绑定过,所以哪怕你调用notifyDataSetChanged(),RecyclerView还是用原来的eventListFiltered,自然看不到任何变化。

另外,你的Adapter里有太多重复的列表(mEvents、eventListFiltered、filteredList、oldList),很容易搞混,建议简化一下,只保留原始数据列表和过滤后的数据列表两个就够了。

具体修复步骤:

1. 重构EventsAdapter,清理冗余列表并修正setFilter方法

public class EventsAdapter extends RecyclerView.Adapter<EventsAdapter.EventsViewHolder>{
    private List<Event> mOriginalEvents; // 保存从Firebase获取的原始完整数据
    private List<Event> mFilteredEvents; // 过滤后的数据,给RecyclerView显示
    private Context mContext;

    public EventsAdapter(Context context, ArrayList<Event> events) {
        mContext = context;
        // 注意:这里要创建列表副本,避免后续修改原始events时影响Adapter里的数据
        mOriginalEvents = new ArrayList<>(events);
        mFilteredEvents = new ArrayList<>(events);
    }

    @Override
    public EventsAdapter.EventsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_event, parent, false);
        return new EventsViewHolder(v);
    }

    @Override
    public void onBindViewHolder(EventsAdapter.EventsViewHolder holder, int position) {
        // 绑定过滤后的列表数据
        holder.bindEvents(mFilteredEvents.get(position));
    }

    @Override
    public int getItemCount() {
        return mFilteredEvents.size();
    }

    // 修正setFilter方法:更新RecyclerView绑定的mFilteredEvents
    public void setFilter(List<Event> filteredList) {
        mFilteredEvents.clear();
        mFilteredEvents.addAll(filteredList);
        notifyDataSetChanged();
    }

    // 新增方法:当Firebase数据加载完成后,更新Adapter的原始数据
    public void updateOriginalData(List<Event> newData) {
        mOriginalEvents.clear();
        mOriginalEvents.addAll(newData);
        mFilteredEvents.clear();
        mFilteredEvents.addAll(newData);
        notifyDataSetChanged();
    }

    // ViewHolder和bindEvents方法保持不变
    public class EventsViewHolder extends RecyclerView.ViewHolder {
        // ... 你的原有代码 ...
    }
}

2. 修正Firebase数据加载后的回调逻辑

原来你是直接给events列表加数据,然后调用notifyDataSetChanged(),但这时候Adapter里的原始数据还是构造时的空列表,后续过滤会出问题。现在换成调用Adapter的updateOriginalData方法:

firebaseFirestore.collection("events").orderBy("time").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(Task<QuerySnapshot> task) {
        if(task.isSuccessful()){
            List<DocumentSnapshot> temp = task.getResult().getDocuments();
            events.clear(); // 先清空原有数据
            for(int i = 0; i < temp.size(); i++){
                // ... 你的日期格式化和Event对象创建代码 ...
                events.add(new Event(...));
            }
            // 用新方法更新Adapter数据
            mAdapter.updateOriginalData(events);
        }
    }
});

3. 优化SearchView的过滤逻辑

每次过滤时最好新建一个列表,避免之前的数据残留:

@Override
public boolean onQueryTextChange(String s) {
    String query = s.toLowerCase().trim();
    List<Event> newList = new ArrayList<>();
    // 这里建议用Adapter里的mOriginalEvents来过滤,而不是Fragment里的events
    // 不过如果你的events和Adapter的mOriginalEvents保持同步也可以
    for(Event event: events){
        String name = event.getEventName().toLowerCase();
        if(name.contains(query)){
            newList.add(event);
        }
    }
    mAdapter.setFilter(newList);
    return true;
}

额外提醒:

  • 尽量不要直接把原始列表的引用传给Adapter,要用new ArrayList<>(originalList)创建副本,避免后续修改原始列表时意外影响Adapter的数据。
  • 如果过滤逻辑复杂,也可以考虑用Android自带的Filter类来实现,不过你的场景用当前的方式也足够。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:45:34