如何使用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
相关产品推荐
相关产品推荐

