Android嵌套RecyclerView使用Volley加载子列表数据问题求解
问题原因分析
1. 所有分类子列表加载相同数据
你使用了全局共用的dataChild集合存储子项数据,每次请求新分类的子菜单时没有清空旧数据,所有分类的子项都往同一个集合累加,最终所有子RecyclerView加载的都是同一个集合的全量数据。
2. onBindViewHolder中变量返回null
Volley是异步网络请求,调用loadChildMenu后请求还没返回,你就立刻执行了打印变量、添加数据的逻辑,此时onSuccess回调还未触发,变量自然为null。
修复方案
核心逻辑调整
- 每个父分类单独维护专属的子数据集合,避免全局数据污染
- 子列表更新逻辑全部放到异步请求成功的回调中执行
- 增加ViewHolder复用校验,避免滑动时数据绑定错乱
- 不要每次请求都新建RequestQueue,建议全局共用单例RequestQueue
具体代码修改
父Adapter的onBindViewHolder逻辑
@Override public void onBindViewHolder(MyViewHolder holder, int position) { ParentModel currentItem = parentModelArrayList.get(position); // 绑定当前分类ID,防止ViewHolder复用导致数据错乱 holder.bindCategoryId(currentItem.getIdCategory()); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(cxt, LinearLayoutManager.HORIZONTAL, false); holder.childRecyclerView.setLayoutManager(layoutManager); holder.childRecyclerView.setHasFixedSize(true); holder.category.setText(currentItem.movieCategory()); // 每个父项单独创建子数据集合 ArrayList<ModelTransaksi> currentChildList = new ArrayList<>(); ChildRecyclerViewAdapter childAdapter = new ChildRecyclerViewAdapter(currentChildList, cxt); holder.childRecyclerView.setAdapter(childAdapter); // 发起当前分类的子菜单请求 holder.loadChildMenu(currentItem.getIdCategory(), new VolleyCallback() { @Override public void onSuccess(String result) { // 校验ViewHolder当前绑定的分类,避免复用错乱 if (holder.getBoundCategoryId() != currentItem.getIdCategory()) { return; } currentChildList.clear(); try { JSONObject obj = new JSONObject(result); JSONArray jArray = obj.getJSONArray("result"); for (int i = 0; i < jArray.length(); i++) { JSONObject jObj = jArray.getJSONObject(i); ModelTransaksi modelTransaksi = new ModelTransaksi(); modelTransaksi.setId(jObj.getInt("idmenu")); modelTransaksi.setName(jObj.getString("name")); modelTransaksi.setImage(jObj.getString("image")); modelTransaksi.setPrice1(jObj.getInt("price1")); modelTransaksi.setPrice2(jObj.getInt("price2")); modelTransaksi.setSize(!jObj.getString("size").equals("0")); currentChildList.add(modelTransaksi); } // 请求完成后更新子列表 childAdapter.notifyDataSetChanged(); } catch (Exception e) { e.printStackTrace(); } } }); }
ViewHolder类逻辑调整
public class MyViewHolder extends RecyclerView.ViewHolder { private int boundCategoryId; // 其他控件声明省略 public MyViewHolder(@NonNull View itemView) { super(itemView); // 控件初始化逻辑省略 } public void bindCategoryId(int categoryId) { this.boundCategoryId = categoryId; } public int getBoundCategoryId() { return boundCategoryId; } public void loadChildMenu(int categoryId, final VolleyCallback callback) { // RequestQueue建议替换为全局单例,避免重复创建消耗性能 RequestQueue requestQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest(Request.Method.POST, Servers.VIEW_TRANSC_URL, new Response.Listener<String>() { @Override public void onResponse(String response) { callback.onSuccess(response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.e("TAG", "Error : " + error.getMessage()); Toast.makeText(context, error.getMessage(), Toast.LENGTH_LONG).show(); } }) { @Nullable @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<String, String>(); params.put("idcat", String.valueOf(categoryId)); return params; } }; requestQueue.add(stringRequest); } }
可选优化
可以将请求完成的子数据缓存到对应的ParentModel实体中,下次滑动到已经加载过的分类时直接读取缓存,不需要重复发起网络请求,提升滑动流畅度。
内容的提问来源于stack exchange,提问作者Rahmad
相关产品推荐
相关产品推荐

