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

如何使用Retrofit解析嵌套JSON并在ExpandableListView中调用数据

没问题,我来一步步帮你搞定嵌套JSON解析和ExpandableListView展示的事儿!

步骤1:定义Retrofit接口

首先得创建Retrofit的API接口,因为你的返回数据是一个ParentData对象的数组,所以接口方法要返回Call<List<ParentData>>:

public interface MenuApi {
    @GET("your-menu-endpoint") // 替换成你实际的接口路径
    Call<List<ParentData>> fetchMenuData();
}
步骤2:初始化Retrofit并发起请求

在你的Activity或者Fragment里,初始化Retrofit实例,然后调用接口获取数据。记得要处理成功和失败的情况:

// 初始化Retrofit
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("your-api-base-url") // 替换成你的API基础地址
        .addConverterFactory(GsonConverterFactory.create())
        .build();

MenuApi menuApi = retrofit.create(MenuApi.class);
Call<List<ParentData>> call = menuApi.fetchMenuData();

call.enqueue(new Callback<List<ParentData>>() {
    @Override
    public void onResponse(Call<List<ParentData>> call, Response<List<ParentData>> response) {
        if (response.isSuccessful() && response.body() != null) {
            // 拿到数据后,交给ExpandableListView处理
            setupExpandableList(response.body());
        } else {
            Toast.makeText(YourActivity.this, "加载菜单数据失败", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onFailure(Call<List<ParentData>> call, Throwable t) {
        Toast.makeText(YourActivity.this, "网络出错啦:" + t.getMessage(), Toast.LENGTH_SHORT).show();
    }
});
步骤3:编写ExpandableListView的自定义适配器

接下来需要一个自定义适配器,继承BaseExpandableListAdapter,用来把父项和子项的数据绑定到视图上:

public class MenuExpandableAdapter extends BaseExpandableListAdapter {
    private Context mContext;
    private List<ParentData> mParentList;

    public MenuExpandableAdapter(Context context, List<ParentData> parentList) {
        mContext = context;
        mParentList = parentList;
    }

    @Override
    public int getGroupCount() {
        return mParentList.size();
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        // 一定要判空,避免空指针!如果父项没有子菜单,返回0
        return mParentList.get(groupPosition).getChildren() != null 
                ? mParentList.get(groupPosition).getChildren().size() 
                : 0;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mParentList.get(groupPosition);
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mParentList.get(groupPosition).getChildren().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    // 渲染父项视图
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        ParentData parentItem = (ParentData) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
        }
        TextView titleTv = convertView.findViewById(android.R.id.text1);
        titleTv.setText(parentItem.getTitle());
        // 给父项标题加个加粗样式,区分开子项
        titleTv.setTypeface(null, Typeface.BOLD);
        return convertView;
    }

    // 渲染子项视图
    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildData childItem = (ChildData) getChild(groupPosition, childPosition);
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(android.R.layout.simple_expandable_list_item_2, parent, false);
        }
        TextView titleTv = convertView.findViewById(android.R.id.text1);
        titleTv.setText(childItem.getTitle());
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true; // 允许子项被点击
    }
}
步骤4:绑定数据到ExpandableListView

最后写一个方法,把拿到的父项数据设置给ExpandableListView:

private void setupExpandableList(List<ParentData> parentList) {
    ExpandableListView expandableLv = findViewById(R.id.your_expandable_list_id); // 替换成你布局里的控件ID
    MenuExpandableAdapter adapter = new MenuExpandableAdapter(this, parentList);
    expandableLv.setAdapter(adapter);

    // 可选操作:默认展开第一个父项
    expandableLv.expandGroup(0);
}
一些小提醒
  • 实体类检查:你的JSON里有些子项(比如Studio下的Build)还有自己的children数组,如果需要展示三级菜单,那你的ChildData类也需要添加ArrayList<ChildData> children字段,和ParentData结构一致;如果只需要两级菜单,现在的实体类就够用。
  • 忽略无用字段:JSON里的roles字段如果用不到,不用在实体类里定义,Gson会自动忽略这些未声明的字段,完全没问题。
  • 空值防护:一定要记得在获取children的时候判空,不然遇到没有子菜单的父项会触发空指针异常,适配器里已经帮你做了这个处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 09:47:34