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

Android Retrofit2实现分类子分类可展开RecyclerView问题求助

解决可展开RecyclerView的子分类显示问题

我帮你排查了代码里的几个关键问题,咱们一步步梳理并解决:

问题核心分析

从你的代码和当前效果来看,主要有三个问题导致子分类显示异常:

  • 子分类循环时的下标错误,导致取到错误数据甚至可能触发数组越界
  • 实体类设计混淆了父、子分类的职责,字段冗余且逻辑混乱
  • 数据存储没有建立父分类与对应子分类的关联,Adapter无法正确映射父-子关系

分步解决方案

1. 先修复最紧急的下标错误

在Activity的子分类循环中,你错误地用了父分类的循环变量i来获取子分类,应该用当前子分类的循环变量j:

// 错误代码
categories.setId(sub.get(i).getSub_id());
categories.setSub_title(sub.get(i).getSub_title());
categories.setSub_img(sub.get(i).getSub_img());

// 正确代码
categories.setId(sub.get(j).getSub_id());
categories.setSub_title(sub.get(j).getSub_title());
categories.setSub_img(sub.get(j).getSub_img());

2. 重构实体类,分离父/子分类职责

同一个Categories类同时承载父、子分类字段会导致逻辑混乱,建议拆分成三个清晰的类:

父分类实体类 ParentCategory

public class ParentCategory {
    @SerializedName("id") @Expose private String id;
    @SerializedName("title") @Expose private String title;
    @SerializedName("img") @Expose private String img;
    @SerializedName("sub_cats") @Expose private List<SubCategory> subCats = null;
    
    // 生成对应的getter和setter方法
}

子分类实体类 SubCategory

public class SubCategory {
    @SerializedName("sub_id") @Expose private String subId;
    @SerializedName("sub_title") @Expose private String subTitle;
    @SerializedName("sub_img") @Expose private String subImg;
    
    // 生成对应的getter和setter方法
}

根响应实体类 CategoryResponse

public class CategoryResponse {
    @SerializedName("cats") @Expose private List<ParentCategory> cats = null;
    @SerializedName("message") @Expose private String message;
    @SerializedName("success") @Expose private Integer success;
    
    // 生成对应的getter和setter方法
}

同时更新Retrofit的API方法:

@GET("cats.php")
Call<CategoryResponse> getCategories();

3. 调整数据处理逻辑,建立父-子关联

不再把父、子分类存到两个独立列表,而是直接使用包含子分类的父分类列表,让Adapter能直接获取每个父项对应的子项:

Call<CategoryResponse> callCats = RetrofitBuilder.getInstance().getApi().getCategories();
callCats.enqueue(new Callback<CategoryResponse>() {
    @Override
    public void onResponse(Call<CategoryResponse> call, Response<CategoryResponse> response) {
        CategoryResponse categoryResponse = response.body();
        if (categoryResponse != null && categoryResponse.getSuccess() == 1){
            List<ParentCategory> parentCategories = categoryResponse.getCats();
            // 直接传入包含子分类的父分类列表
            ExpandableRecyclerViewAdapter adapter = new ExpandableRecyclerViewAdapter(getApplicationContext(), parentCategories);
            expanderRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
            expanderRecyclerView.setAdapter(adapter);
        }
    }

    @Override
    public void onFailure(Call<CategoryResponse> call, Throwable t) {
        Toast.makeText(BuyerDashboard.this, t.getMessage(), Toast.LENGTH_SHORT).show();
    }
});

4. 适配可展开RecyclerView的Adapter逻辑

调整ExpandableRecyclerViewAdapter,使其接收父分类列表,并管理展开/折叠状态:

public class ExpandableRecyclerViewAdapter extends RecyclerView.Adapter<ExpandableRecyclerViewAdapter.ParentViewHolder> {
    private Context context;
    private List<ParentCategory> parentCategoryList;
    // 记录每个父分类的展开状态
    private Map<Integer, Boolean> expandStatusMap = new HashMap<>();

    public ExpandableRecyclerViewAdapter(Context context, List<ParentCategory> parentCategoryList) {
        this.context = context;
        this.parentCategoryList = parentCategoryList;
        // 初始化所有父分类为折叠状态
        for (int i = 0; i < parentCategoryList.size(); i++) {
            expandStatusMap.put(i, false);
        }
    }

    @NonNull
    @Override
    public ParentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.cat_items, parent, false);
        return new ParentViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ParentViewHolder holder, int position) {
        ParentCategory parent = parentCategoryList.get(position);
        holder.tvParentTitle.setText(parent.getTitle());
        
        // 根据状态切换子RecyclerView显示/隐藏
        boolean isExpanded = expandStatusMap.get(position);
        holder.subRecyclerView.setVisibility(isExpanded ? View.VISIBLE : View.GONE);

        // 初始化子分类Adapter
        InnerRecyclerViewAdapter subAdapter = new InnerRecyclerViewAdapter(context, parent.getSubCats());
        holder.subRecyclerView.setLayoutManager(new LinearLayoutManager(context));
        holder.subRecyclerView.setAdapter(subAdapter);

        // 父项点击事件:切换展开状态
        holder.itemView.setOnClickListener(v -> {
            expandStatusMap.put(position, !isExpanded);
            notifyItemChanged(position);
        });
    }

    @Override
    public int getItemCount() {
        return parentCategoryList.size();
    }

    public static class ParentViewHolder extends RecyclerView.ViewHolder {
        TextView tvParentTitle;
        RecyclerView subRecyclerView;

        public ParentViewHolder(@NonNull View itemView) {
            super(itemView);
            tvParentTitle = itemView.findViewById(R.id.tv_cat_title);
            subRecyclerView = itemView.findViewById(R.id.sub_recycler_view);
        }
    }
}

对应的子分类Adapter也要适配SubCategory类:

public class InnerRecyclerViewAdapter extends RecyclerView.Adapter<InnerRecyclerViewAdapter.SubViewHolder> {
    private Context context;
    private List<SubCategory> subCategoryList;

    public InnerRecyclerViewAdapter(Context context, List<SubCategory> subCategoryList) {
        this.context = context;
        this.subCategoryList = subCategoryList;
    }

    @NonNull
    @Override
    public SubViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.sub_cat_items, parent, false);
        return new SubViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull SubViewHolder holder, int position) {
        SubCategory sub = subCategoryList.get(position);
        holder.tvSubTitle.setText(sub.getSubTitle());
        // 后续可以添加Glide/Picasso加载图片的逻辑
    }

    @Override
    public int getItemCount() {
        return subCategoryList.size();
    }

    public static class SubViewHolder extends RecyclerView.ViewHolder {
        TextView tvSubTitle;

        public SubViewHolder(@NonNull View itemView) {
            super(itemView);
            tvSubTitle = itemView.findViewById(R.id.tv_sub_cat_title);
        }
    }
}

额外优化建议

  • 确保cat_items.xml中的子RecyclerView初始状态设为android:visibility="gone"
  • 可以给父分类标题添加展开/折叠图标(比如向上/向下箭头),提升用户体验
  • 图片加载建议使用Glide或Picasso库,避免直接加载网络图片导致的性能问题

内容的提问来源于stack exchange,提问作者Hamza Afzal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:55:33