Android Studio中RecyclerView实时搜索筛选功能不生效问题求解
RecyclerView+SearchView实时过滤无响应问题修复
核心错误点
- 搜索回调逻辑错误:
onQueryTextChange每次触发时都新建了一个未绑定RecyclerView的Adapter实例,对这个新实例调用filter完全不会影响当前页面正在显示的列表,这是功能完全无响应的核心原因。 - 过滤数据源逻辑错误:空搜索词分支中,过滤数据源取的是已经被修改过的当前显示列表
retrievedResponses,而非存全量原始数据的retrievedResponsesAll,会导致首次过滤后清空搜索词无法恢复全量列表。 - 未重写
getFilter()方法返回自定义Filter实例,父类默认返回null,后续会触发空指针。 - 自定义Filter未给
FilterResults设置count字段,部分Android版本会判定结果为空,不触发列表刷新。
可直接复用的修正代码
1. Activity侧修正(将Adapter设为成员变量,仅初始化一次)
// 声明为Activity成员变量,不要在菜单创建方法里局部声明 private BalanceReportAdapter reportAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_balance_report); // 完成RecyclerView初始化、布局管理器配置等逻辑 // 初始化Adapter并绑定到RecyclerView,仅执行一次 reportAdapter = new BalanceReportAdapter(jsonResponses, BalanceReport.this); recyclerView.setAdapter(reportAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.search, menu); MenuItem item = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) item.getActionView(); searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { searchView.clearFocus(); return false; } @Override public boolean onQueryTextChange(String newText) { // 直接调用已绑定RecyclerView的Adapter实例的过滤方法 reportAdapter.getFilter().filter(newText); return false; } }); return super.onCreateOptionsMenu(menu); }
2. Adapter侧修正(完善Filter逻辑,补全必要方法)
public class BalanceReportAdapter extends RecyclerView.Adapter<BalanceReportAdapter.ViewHolder> implements Filterable { // 当前展示在列表上的数据源 private List<BalanceReportModel> retrievedResponses; // 全量原始数据源,仅用于过滤匹配,永远不直接修改 private List<BalanceReportModel> retrievedResponsesAll; private Context context; private Filter customFilter; public BalanceReportAdapter(List<BalanceReportModel> dataList, Context context) { this.retrievedResponses = new ArrayList<>(dataList); // 拷贝一份全量数据用于搜索 this.retrievedResponsesAll = new ArrayList<>(dataList); this.context = context; } @Override public Filter getFilter() { if (customFilter == null) { customFilter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { List<BalanceReportModel> filteredResult = new ArrayList<>(); // 搜索词为空时直接返回全量数据 if (constraint == null || constraint.length() == 0) { filteredResult.addAll(retrievedResponsesAll); } else { String keyword = constraint.toString().toLowerCase().trim(); for (BalanceReportModel item : retrievedResponsesAll) { // 可在此处扩展多字段匹配逻辑 if (item.getcustomer().toLowerCase().contains(keyword)) { filteredResult.add(item); } } } FilterResults results = new FilterResults(); results.values = filteredResult; results.count = filteredResult.size(); return results; } @SuppressLint("NotifyDataSetChanged") @Override protected void publishResults(CharSequence constraint, FilterResults results) { retrievedResponses.clear(); retrievedResponses.addAll((List<BalanceReportModel>) results.values); notifyDataSetChanged(); } }; } return customFilter; } // 其余onCreateViewHolder、onBindViewHolder等原有逻辑保持不变 }
补充说明:如果后续有接口拉取新数据刷新列表的逻辑,更新
retrievedResponses的同时一定要同步更新retrievedResponsesAll的全量数据,否则新增内容不会进入搜索匹配范围。如果对列表刷新性能有要求,可以把notifyDataSetChanged()替换为DiffUtil差分刷新,减少不必要的item重绘。
内容的提问来源于stack exchange,提问作者Gabriel Chinnappan
相关产品推荐
相关产品推荐

