Android Retrofit解析嵌套JSON遇动态键:需定义何种POJO?
解决Retrofit解析动态键嵌套JSON的问题
嗨,这个动态键的JSON解析问题我之前也碰到过,其实用Retrofit搭配Gson(Retrofit默认的解析器)很容易搞定,核心思路是用Map承接外层的动态键,同时定义固定结构的POJO对应内层的对象,具体步骤如下:
1. 定义内层固定结构的POJO
你的JSON里,每个动态键对应的内层对象结构是固定的(都包含PDF、URL、image等字段),所以先给这个内层对象写一个POJO类:
Java版本
import com.google.gson.annotations.SerializedName; public class ContentItem { // 用@SerializedName保证和JSON键名严格对应,避免大小写或命名风格差异 @SerializedName("PDF") private String pdf; @SerializedName("URL") private String url; @SerializedName("image") private String image; @SerializedName("shortDescription") private String shortDescription; @SerializedName("timestamp") private String timestamp; @SerializedName("title") private String title; // 生成getter和setter方法,或者用Lombok的@Data注解简化代码 public String getPdf() { return pdf; } public void setPdf(String pdf) { this.pdf = pdf; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public String getShortDescription() { return shortDescription; } public void setShortDescription(String shortDescription) { this.shortDescription = shortDescription; } public String getTimestamp() { return timestamp; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
Kotlin版本(更简洁)
import com.google.gson.annotations.SerializedName data class ContentItem( @SerializedName("PDF") val pdf: String, @SerializedName("URL") val url: String, val image: String, val shortDescription: String, val timestamp: String, val title: String )
2. 用Map作为Retrofit接口的返回类型
因为外层的键是动态变化的时间字符串,没法用固定的字段来对应,所以直接用Map<String, ContentItem>来接收整个JSON对象。这样Gson会自动把每个动态键映射成Map的key,对应的内层对象映射成Map的value:
Java版本接口
import retrofit2.Call; import retrofit2.http.GET; public interface ApiService { // 替换成你的实际接口地址 @GET("your-api-endpoint") Call<Map<String, ContentItem>> getDynamicContent(); }
Kotlin版本接口(支持协程)
import retrofit2.http.GET import retrofit2.Response interface ApiService { @GET("your-api-endpoint") suspend fun getDynamicContent(): Response<Map<String, ContentItem>> }
3. 调用接口并解析数据
拿到Map之后,你可以通过遍历的方式处理每个动态键对应的内容:
Java版本调用示例
// 假设你已经初始化好了Retrofit实例 ApiService apiService = retrofit.create(ApiService.class); Call<Map<String, ContentItem>> call = apiService.getDynamicContent(); call.enqueue(new Callback<Map<String, ContentItem>>() { @Override public void onResponse(Call<Map<String, ContentItem>> call, Response<Map<String, ContentItem>> response) { if (response.isSuccessful() && response.body() != null) { Map<String, ContentItem> contentMap = response.body(); // 遍历Map处理每个条目 for (Map.Entry<String, ContentItem> entry : contentMap.entrySet()) { String dynamicTimeKey = entry.getKey(); // 就是JSON里的时间字符串,比如"Fri Mar 23 2018 17:35:36 GMT+0530 (IST)" ContentItem item = entry.getValue(); // 访问item的属性 System.out.println("标题:" + item.getTitle()); System.out.println("描述:" + item.getShortDescription()); } } } @Override public void onFailure(Call<Map<String, ContentItem>> call, Throwable t) { // 处理请求失败的逻辑,比如打印错误信息 t.printStackTrace(); } });
Kotlin版本调用示例(协程)
// 在协程作用域内调用 lifecycleScope.launch { val response = apiService.getDynamicContent() if (response.isSuccessful) { val contentMap = response.body() ?: return@launch contentMap.forEach { (timeKey, item) -> println("时间键:$timeKey") println("标题:${item.title}") println("描述:${item.shortDescription}") } } else { // 处理请求失败 println("请求失败:${response.message()}") } }
这样就能完美解析这种动态键的嵌套JSON啦,核心就是利用Map的键值对特性来适配动态的JSON键,同时用固定POJO来约束内层的结构。
内容的提问来源于stack exchange,提问作者chin87
相关产品推荐
相关产品推荐

