Android Studio实现SearchView传参调用API并展示RecyclerView求助
问题分析与修复方案
现有代码的核心问题
- API请求URL错误:USDA搜索API的查询参数是
query,你的URL写成了?=,应该改为?query=,否则API无法识别搜索关键词。 - JSON键名错误:
response.getJSONArray(" foods")中键名带了开头空格,正确的键是"foods",这会直接导致JSON解析异常。 - 无请求防抖:用户每输入一个字符就发起请求,会产生大量无效请求,既浪费资源也可能触发API频率限制。
- 数据源未重置:每次新搜索前未清空
foodModelList,旧数据会和新数据叠加显示。 - Toast未触发显示:
Toast.makeText()后缺少.show()方法,错误提示不会弹出。 - 变量名拼写错误:
proteingrmas.toString()应为proteingrams.toString(),会导致编译或运行错误。 - RecyclerView未更新:添加数据后未通知适配器刷新,列表不会显示新数据。
- JSON解析逻辑错误:USDA API的
value字段嵌套在foodNutrients数组中,直接获取value会抛出异常,需要正确解析嵌套结构。
修复后的完整代码
1. 防抖工具与请求逻辑
先在Activity中声明防抖用的Handler和Runnable:
private Handler searchHandler = new Handler(); private Runnable searchRunnable;
然后修改onQueryTextChange方法:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { // 移除之前的延迟请求,实现防抖 if (searchRunnable != null) { searchHandler.removeCallbacks(searchRunnable); } // 输入为空时清空列表 if (TextUtils.isEmpty(newText)) { foodModelList.clear(); recyclerViewAdapter.notifyDataSetChanged(); return true; } // 延迟500ms发起请求,用户停止输入后才执行 searchRunnable = () -> { // 修正URL参数 String url = "https://fdc.nal.usda.gov/fdc/v1/foods/search?query=" + newText + "&dataType=Foundation,SR%20Legacy&api_key=my_apikey"; JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, response -> { try { // 清空旧数据 foodModelList.clear(); JSONArray jsonArray = response.getJSONArray("foods"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject foodObj = jsonArray.getJSONObject(i); String foodName = foodObj.getString("description"); // 解析蛋白质含量(嵌套在foodNutrients数组中) String proteinGrams = "0"; JSONArray nutrientsArray = foodObj.getJSONArray("foodNutrients"); for (int j = 0; j < nutrientsArray.length(); j++) { JSONObject nutrientObj = nutrientsArray.getJSONObject(j); if (nutrientObj.getString("nutrientName").equals("Protein")) { proteinGrams = nutrientObj.getString("value"); break; } } setData(foodName, proteinGrams); } // 通知适配器更新 recyclerViewAdapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(SearchFoods.this, "数据解析失败", Toast.LENGTH_SHORT).show(); } }, error -> { String errorMsg = error.getMessage() != null ? error.getMessage() : "请求失败"; Toast.makeText(SearchFoods.this, errorMsg, Toast.LENGTH_SHORT).show(); }); requestQueue.add(jsonObjectRequest); }; searchHandler.postDelayed(searchRunnable, 500); return true; } });
2. 修复setData方法
public void setData(String foodname, String proteingrams) { // 修正变量名拼写错误,避免空指针 String safeFoodName = foodname != null ? foodname : "未知食物"; String safeProtein = proteingrams != null ? proteingrams : "0"; foodModelList.add(new FoodModel(safeFoodName, "70", "14", safeProtein, "47.6", "11.9", "2.7", "1")); }
额外优化建议
- API密钥安全:不要把API密钥硬编码在代码中,建议放在
local.properties文件中,通过BuildConfig读取。 - 使用Gson简化解析:可以用Gson将JSON直接映射到实体类,避免手动解析JSON的繁琐和错误,比如创建
FoodResponse、Food、FoodNutrient等实体类。 - 分页加载:如果API支持分页,可以添加分页逻辑,避免一次性加载过多数据导致列表卡顿。
- 网络状态判断:发起请求前检查网络连接,给用户友好提示。
内容的提问来源于stack exchange,提问作者CAM3R0N
相关产品推荐
相关产品推荐

