Android开发中置于RecyclerView内的SearchView搜索过滤功能失效问题
问题根因排查
- 过滤逻辑初始化错误:原代码在
performFiltering中先把当前已展示的data集合拷贝到过滤列表中,而非创建空列表。导致搜索时会把上一次残留的不匹配数据一并保留在结果中,关键词清空时还会出现全量数据和残留数据重复的问题,完全无法实现正确的过滤效果。 - 集合引用绑定错误:构造方法中直接将外部传入的
data集合赋值给适配器内部变量,没有做独立拷贝,容易出现外部修改集合时,适配器内部数据和全量备份集合不同步的问题。 - 多ViewType适配缺失:将SearchView作为RecyclerView内部item放置时,原适配器没有做布局类型区分,会直接把SearchView布局当成普通数据item绑定,触发类型转换异常、布局错乱的运行问题,也无法正确捕获SearchView的输入回调。
修复后的完整实现
public class SearchAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable { // 定义布局类型常量 private static final int VIEW_TYPE_SEARCH_HEADER = 0; private static final int VIEW_TYPE_DATA_ITEM = 1; private Context context; // 当前展示的搜索结果数据集 private ArrayList<String> showDataList = new ArrayList<>(); // 全量原始备份数据集 private ArrayList<String> fullDataList = new ArrayList<>(); public SearchAdapter(Context context, ArrayList<String> data) { this.context = context; // 对内部维护的集合做独立拷贝,解耦外部传入的集合引用 this.showDataList = new ArrayList<>(data); this.fullDataList = new ArrayList<>(data); } @Override public int getItemViewType(int position) { // 列表第一个位置固定为SearchView头部布局 if (position == 0) { return VIEW_TYPE_SEARCH_HEADER; } return VIEW_TYPE_DATA_ITEM; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_SEARCH_HEADER) { // 加载包含SearchView的头布局 View headerView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_search_header, parent, false); return new SearchHeaderViewHolder(headerView); } // 加载普通数据项布局 View dataView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycledata, parent, false); return new DataItemViewHolder(dataView); } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { int currentViewType = getItemViewType(holder.getAdapterPosition()); if (currentViewType == VIEW_TYPE_SEARCH_HEADER) { SearchHeaderViewHolder headerHolder = (SearchHeaderViewHolder) holder; // 直接绑定SearchView的输入回调,自动触发过滤 headerHolder.searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { getFilter().filter(newText); return true; } }); return; } // 绑定普通数据项,因头部占位1个位置,需对索引做偏移 DataItemViewHolder dataHolder = (DataItemViewHolder) holder; String itemContent = showDataList.get(position - 1); dataHolder.textView.setText(itemContent); } @Override public int getItemCount() { // 总条目数 = 1个搜索头 + 当前展示的数据条数 return showDataList.size() + 1; } @Override public Filter getFilter() { return new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { // 初始化空的过滤结果列表,不提前拷贝当前展示数据 ArrayList<String> filterResultList = new ArrayList<>(); String keyword = constraint.toString().toLowerCase().trim(); if (keyword.isEmpty()) { // 关键词为空时,直接加载全量数据 filterResultList.addAll(fullDataList); } else { // 遍历全量数据匹配关键词,仅将符合条件的条目加入结果 for (String item : fullDataList) { if (item.toLowerCase().contains(keyword)) { filterResultList.add(item); } } } FilterResults results = new FilterResults(); results.values = filterResultList; return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { showDataList.clear(); showDataList.addAll((ArrayList<String>) results.values); notifyDataSetChanged(); } }; } // 搜索头布局ViewHolder class SearchHeaderViewHolder extends RecyclerView.ViewHolder { SearchView searchView; public SearchHeaderViewHolder(@NonNull View itemView) { super(itemView); searchView = itemView.findViewById(R.id.search_view); } } // 普通数据项ViewHolder class DataItemViewHolder extends RecyclerView.ViewHolder { TextView textView; public DataItemViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.textview); } } }
关键修复说明
- 重构过滤核心逻辑:过滤结果从空集合开始构建,完全基于全量备份数据做关键词匹配,彻底解决旧数据残留、重复展示的问题。
- 解决集合引用不同步问题:适配器内部维护的展示数据、全量备份数据均做独立内存拷贝,和外部传入的集合解耦,避免集合修改导致的状态异常。
- 适配SearchView内嵌场景:通过多ViewType区分头部搜索布局和普通数据项,解决布局绑定的类型转换异常;同时直接在搜索头绑定逻辑中监听输入变化,自动触发过滤流程,无需外部手动调用。
- 修正位置偏移问题:针对头部布局的占位场景,绑定普通数据时对item位置做偏移处理,避免索引越界、数据错绑的问题。
内容的提问来源于stack exchange,提问作者Muhammad Waseem Haider
相关产品推荐
相关产品推荐

