如何在Android中使用Retrofit解析JSON数组
Hey there! Let's walk through exactly how to parse this nested menu JSON structure using Retrofit in your Android project. I'll break it down step by step so you can follow along easily.
1. 先定义匹配JSON结构的数据模型
First things first: we need to create data classes (or POJOs for Java) that mirror the JSON structure. Notice the nested subMenus array—this means our model will reference itself recursively.
Kotlin 数据类
Kotlin's data classes make this super clean, and we'll use nullable types for fields that can be null (like icon and desc):
data class Menu( val name: String, val link: String, val menuId: String, val icon: String?, val desc: String?, val selected: Boolean, val subMenus: List<Menu> // 递归定义子菜单列表 )
Java POJO类
If you're using Java, you'll need a standard POJO with getters/setters (or use Lombok to auto-generate them). We'll use @SerializedName to explicitly map fields (this is optional if your field names match the JSON exactly, but it's safer for future changes):
import com.google.gson.annotations.SerializedName; import java.util.List; public class Menu { @SerializedName("name") private String name; @SerializedName("link") private String link; @SerializedName("menuId") private String menuId; @SerializedName("icon") private String icon; @SerializedName("desc") private String desc; @SerializedName("selected") private boolean selected; @SerializedName("subMenus") private List<Menu> subMenus; // Getters and Setters public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getMenuId() { return menuId; } public void setMenuId(String menuId) { this.menuId = menuId; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } public List<Menu> getSubMenus() { return subMenus; } public void setSubMenus(List<Menu> subMenus) { this.subMenus = subMenus; } }
2. 添加Retrofit和Gson依赖
Add these dependencies to your app-level build.gradle file (use the latest stable versions if available):
dependencies { // Retrofit核心库 implementation 'com.squareup.retrofit2:retrofit:2.9.0' // Gson转换器,用于将JSON解析为我们的数据模型 implementation 'com.squareup.retrofit2:converter-gson:2.9.0' }
3. 创建Retrofit API接口
Define an interface to describe your API request. Based on the JSON you provided, the root object is a single Menu (not an array)—adjust this if your actual API returns a list of menus:
import retrofit2.Call import retrofit2.http.GET interface MenuApiService { // 将"menu-endpoint"替换为你的实际API端点路径 @GET("menu-endpoint") fun fetchMenu(): Call<Menu> // 如果你的API返回菜单数组,改为下面这行: // fun fetchMenus(): Call<List<Menu>> }
4. 初始化Retrofit实例
Set up Retrofit with your API base URL and the Gson converter:
val retrofit = Retrofit.Builder() .baseUrl("https://your-api-base-url.com/") // 替换为你的实际基础URL .addConverterFactory(GsonConverterFactory.create()) .build() val menuApi = retrofit.create(MenuApiService::class.java)
5. 发起请求并解析数据
Use Retrofit's asynchronous enqueue method to fetch and parse the data (this avoids blocking the main thread):
menuApi.fetchMenu().enqueue(object : retrofit2.Callback<Menu> { override fun onResponse(call: Call<Menu>, response: retrofit2.Response<Menu>) { if (response.isSuccessful) { val rootMenu = response.body() rootMenu?.let { // 成功解析菜单数据!现在可以开始处理它了 // 示例:获取Dashboard子菜单 val dashboardMenu = it.subMenus.firstOrNull { menu -> menu.menuId == "das" } dashboardMenu?.let { Log.d("MenuParser", "Dashboard Link: ${it.link}") } // 递归遍历所有嵌套菜单 traverseMenu(it) } } else { // 处理非2xx状态码的响应 Log.e("MenuParser", "Request failed with code: ${response.code()}") } } override fun onFailure(call: Call<Menu>, t: Throwable) { // 处理网络错误或请求失败 Log.e("MenuParser", "Request failed: ${t.message}") } }) // 递归遍历所有菜单的辅助函数 private fun traverseMenu(menu: Menu) { Log.d("MenuParser", "Menu Name: ${menu.name}, ID: ${menu.menuId}") menu.subMenus.forEach { subMenu -> traverseMenu(subMenu) } }
关键注意事项
- 递归结构处理:
subMenus字段定义为List<Menu>,Gson会自动递归解析嵌套的JSON数组,无需额外配置。 - 可空字段处理:
icon和desc可能为null,所以Kotlin中使用可空类型、Java中允许字段为null是避免解析错误的关键。 - 根对象类型确认:务必确认你的API返回的是单个
Menu对象还是Menu数组,对应调整API接口和回调的泛型类型。 - 线程安全:Retrofit的
enqueue方法在后台线程执行请求,回调结果在主线程返回,所以可以直接在回调中更新UI。
内容的提问来源于stack exchange,提问作者Deepak Rao

