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
相关产品推荐
相关产品推荐

