You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 00:45:01