如何用Retrofit解析JSON的offers字段并映射到Offers实体类?
解决Retrofit解析包含result和offers字段的JSON问题
你的核心问题是API返回的是包含result和offers的顶层对象,而非直接的Offers数组,同时数据类存在字段不匹配的情况,下面是分步解决方案:
1. 创建顶层响应数据类
先定义一个包裹整个API响应的数据类,对应返回的JSON结构:
data class OfferResponse( val result: Boolean, val offers: List<Offers> )
2. 修正Offers数据类的字段匹配问题
你的数据类有3处和JSON字段不匹配,会导致解析失败,需调整:
- JSON中
lmd_id是字符串类型,你定义为Int会解析错误,改为String(后续使用时可再转Int) - JSON中
smartLink是驼峰命名,数据类里smartlink大小写不一致,用@SerializedName映射 - JSON中
offer_text对应数据类的long_offer,同样用@SerializedName映射
修正后的代码:
import com.google.gson.annotations.SerializedName data class Offers ( val lmd_id: String, val store: String?, val merchant_homepage: String?, @SerializedName("offer_text") val long_offer: String?, val title: String?, val description: String?, val code: String?, val terms_and_conditions: String?, val categories: String?, val featured: String?, val publisher_exclusive: String?, val url: String?, @SerializedName("smartLink") val smartlink: String?, val image_url: String?, val type: String?, val offer: String?, val offer_value: String?, val status: String?, val start_date: String?, val end_date: String? )
3. 修改DealsService接口
将返回类型从List<Offers>改为OfferResponse,对应完整的API响应结构:
interface DealsService { @GET("getOffers/?API_KEY=$api_key&incremental=1&format=json") suspend fun getOffers(): OfferResponse }
4. 调整Fragment中的调用逻辑
现在需要先获取完整响应,再从中取出offers列表,同时添加异常处理避免崩溃:
val dealsService = DealsNetwork.getRetrofitClient().create(DealsService::class.java) // 建议用viewLifecycleOwner的协程Scope,避免内存泄漏 viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { try { // 获取完整响应对象 val response = dealsService.getOffers() // 提取offers列表 val offersList = response.offers withContext(Dispatchers.Main) { val rvDealsAdapter = DealsListRecyclerAdapter(offersList, dealsViewModel) binding.rvDealsList.layoutManager = layoutManager binding.rvDealsList.adapter = rvDealsAdapter } } catch (e: Exception) { // 处理网络请求或解析错误,比如打印日志、提示用户 e.printStackTrace() withContext(Dispatchers.Main) { // 可在此显示错误提示,比如Toast } } }
额外注意事项
- 确保
api_key有效,避免因权限问题返回错误响应 - 如果必须将
lmd_id作为Int使用,可在数据类中保留val lmd_id: Int,Gson会自动将合法数字字符串转为Int,但遇到非数字值会崩溃,需谨慎 - 避免直接创建
CoroutineScope,优先使用viewLifecycleOwner.lifecycleScope或viewModelScope,防止内存泄漏
内容的提问来源于stack exchange,提问作者Kidus
相关产品推荐
相关产品推荐

