Android Fragment Toolbar中SearchView搜索无效果问题排查与实现
排查SearchView无结果显示的问题及正确实现方案
我看了你的代码,能发现几个导致搜索无结果的关键问题,咱们一步步来解决:
核心问题分析
错误1:过滤后传递了原列表而非过滤结果
在onQueryTextChange方法里,你明明已经遍历生成了过滤后的filteredList,但最后却调用adapter.setFilter(itemrestaurants),相当于把原始未过滤的列表重新传给适配器,自然看不到任何搜索结果。错误2:大小写匹配逻辑不一致+冗余操作
你已经把搜索关键词newText转成了小写,但判断餐厅名称时又多做了一次newText.toLowerCase()的冗余操作;更关键的是,餐厅地址row.getRestaurant_address()没转小写,会导致用户搜索"main"时,匹配不到"Main Street"这类大小写不一致的地址。错误3:缺少原始数据备份,多次过滤会丢失数据
你现在直接基于itemrestaurants做过滤,但如果第一次过滤后,这个列表的内容被替换成过滤后的子集,后续的过滤就会基于这个缩小的列表,而不是全部原始餐厅数据,最终导致搜索结果越来越少甚至无结果。
修正后的关键代码实现
1. 调整成员变量,添加原始数据备份
public class Restaurant extends Fragment{ RecyclerView restaurant_recycler; RestaurantsAdapter adapter; private ProgressDialog sweetProgressDialog; SessionManager sessionManager; List<Restaurant_model> itemrestaurants; // 新增:保存所有原始餐厅数据的列表 private List<Restaurant_model> originalRestaurants; private Context mContext; // ... 其他代码 }
2. 初始化原始列表,并在网络请求后同步数据
在onCreateView里初始化原始列表:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.activity_restaurant, container, false); restaurant_recycler = (RecyclerView) v.findViewById(R.id.recycler_view_restaurant); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false); itemrestaurants = new ArrayList<>(); // 初始化原始数据列表 originalRestaurants = new ArrayList<>(); adapter = new RestaurantsAdapter(getContext(), itemrestaurants); restaurant_recycler.setLayoutManager(mLayoutManager); restaurant_recycler.setItemAnimator(new DefaultItemAnimator()); restaurant_recycler.setAdapter(adapter); sweetProgressDialog = new ProgressDialog(getContext(), R.style.MyAlertDialogStyle); sessionManager = new SessionManager(getContext()); show_restaurants(); return v; }
在show_restaurants的网络请求成功回调里,同步原始数据:
try { Log.e("tag", "response " + response); JSONArray array = new JSONArray(response); // 清空列表,避免重复添加数据 itemrestaurants.clear(); originalRestaurants.clear(); for (int i = 0; i < array.length(); i++) { JSONObject thisOBj = (JSONObject) array.get(i); Restaurant_model restaurant = new Restaurant_model( thisOBj.getString("id"), thisOBj.getString("name"), thisOBj.getString("address"), thisOBj.getString("image") ); itemrestaurants.add(restaurant); originalRestaurants.add(restaurant); } adapter.notifyDataSetChanged(); } catch (JSONException e) { // 保留你的异常处理代码 if (sweetProgressDialog.isShowing()) { sweetProgressDialog.dismiss(); } Log.i("myTag", e.toString()); Toast.makeText(getContext(), "Parsing error", Toast.LENGTH_SHORT).show(); }
3. 修正onQueryTextChange方法
@Override public boolean onQueryTextChange(String newText) { newText = newText.toLowerCase().trim(); // 去掉首尾空格,优化搜索体验 List<Restaurant_model> filteredList = new ArrayList<>(); // 基于原始数据列表做过滤,保证每次搜索都是完整数据集 for (Restaurant_model row : originalRestaurants) { String restaurantName = row.getRestaurant_name().toLowerCase(); String restaurantAddress = row.getRestaurant_address().toLowerCase(); // 名称或地址包含关键词就加入过滤列表 if (restaurantName.contains(newText) || restaurantAddress.contains(newText)) { filteredList.add(row); } } // 传递过滤后的列表给适配器 adapter.setFilter(filteredList); return true; }
4. 确保适配器的setFilter方法正确实现
你的RestaurantsAdapter里必须有正确的setFilter方法,用来更新数据源并通知RecyclerView刷新:
public class RestaurantsAdapter extends RecyclerView.Adapter<RestaurantsAdapter.ViewHolder> { private List<Restaurant_model> mRestaurantList; private Context mContext; // 构造方法 public RestaurantsAdapter(Context context, List<Restaurant_model> restaurantList) { mContext = context; mRestaurantList = restaurantList; } // 过滤方法 public void setFilter(List<Restaurant_model> filteredList) { mRestaurantList = filteredList; notifyDataSetChanged(); // 必须调用此方法通知RecyclerView更新UI } // ... 其他ViewHolder、onCreateViewHolder、onBindViewHolder等方法 }
5. 优化onQueryTextSubmit方法
@Override public boolean onQueryTextSubmit(String query) { // 提交搜索后隐藏软键盘,提升体验 View view = getActivity().getCurrentFocus(); if (view != null) { InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } return true; }
总结
修改完成后,你的SearchView应该就能正常显示过滤结果了。核心要点是:
- 始终基于原始完整数据做过滤,避免多次过滤后数据丢失
- 确保过滤后的列表正确传递给适配器
- 适配器必须调用
notifyDataSetChanged()通知RecyclerView刷新UI
内容的提问来源于stack exchange,提问作者Ehtisham habib
相关产品推荐
相关产品推荐

