Android Kotlin中Retrofit读取API时productsDetalys字段为null的问题
问题:Retrofit解析JSON时
productsDetalys字段始终返回null 我正在Android Kotlin中使用Retrofit读取API返回的JSON数据,想要获取productsDetalys下的内容。目前可以正常读取orders_id、customers_id等字段,但productsDetalys始终返回null。
API返回的JSON数据
{"body": [ { "orders_id": "52", "customers_id": "1", "customers_name": "Nida Verkkopalvelu", "customers_company": "Etäisyys 2.3 km", "customers_street_address": "Suoratie 40", "customers_suburb": "", "customers_city": "Porvoo", "customers_postcode": "06100", "customers_state": "", "customers_country": "Finland", "customers_telephone": "09444744", "customers_email_address": "test@nida.fi", "delivery_name": "Nida Verkkopalvelu", "delivery_company": "Etäisyys 2.3 km", "delivery_street_address": "Suoratie 40", "delivery_suburb": "", "delivery_city": "Porvoo", "delivery_postcode": "06100", "delivery_state": "", "delivery_country": "Finland", "payment_method": "Paytrail - Online Payment", "payment_module_code": "paytrail", "shipping_method": "Per Item (Best Way)", "shipping_module_code": "item", "coupon_code": "", "date_purchased": "2023-04-10 10:01:49", "orders_status": "2", "currency": "EUR", "currency_value": "1.000000", "order_total": "55.00", "order_tax": "0.00", "language_code": "en", "comments": "", "productsDetalys": [ [ { "orders_products_id": "111", "products_name": "Book", "products_price": "0.00", "final_price": "52.50", "products_tax": "0.00", "products_quantity": 1, "products_options": "Version", "products_options_values": "Book Hard Cover", "options_values_price": "52.50" } ] ] } ], "itemCount": 1 }
当前使用的数据模型类
OrderDetailsModelClass
data class OrderDetailsModelClass( val body: List<BodyOrderDetails>, val itemCount: Int )
BodyOrderDetails
data class BodyOrderDetails( val comments: String, val coupon_code: String, val currency: String, val currency_value: String, val customers_city: String, val customers_company: String, val customers_country: String, val customers_email_address: String, val customers_id: String, val customers_name: String, val customers_postcode: String, val customers_state: String, val customers_street_address: String, val customers_suburb: String, val customers_telephone: String, val date_purchased: String, val delivery_city: String, val delivery_company: String, val delivery_country: String, val delivery_name: String, val delivery_postcode: String, val delivery_state: String, val delivery_street_address: String, val delivery_suburb: String, val language_code: String, val order_tax: String, val order_total: String, val orders_id: String, val orders_status: String, val payment_method: String, val payment_module_code: String, val ProductsDetalys: List<List<ProductsDetalys>>, val shipping_method: String, val shipping_module_code: String )
ProductsDetalys
data class ProductsDetalys( val final_price: String, val options_values_price: String, val orders_products_id: String, val products_name: String, val products_options: String, val products_options_values: String, val products_price: String, val products_quantity: Int, val products_tax: String )
Retrofit接口与MainActivity实现
ProductDetailsApi接口
interface ProductDetailsApi { @GET() fun getProductDetails() : Call<OrderDetailsModelClass> }
MainActivity代码
class MainActivity : AppCompatActivity() { lateinit var orderDetailsList: List<BodyOrderDetails> lateinit var productsDetailsList: List<ProductsDetalys> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_order_details) val retrofitProductDetails = Retrofit.Builder() .baseUrl("https://pizzapalvelu.fi/158a/") .addConverterFactory(GsonConverterFactory.create()).build() val apiProductDetailsList = retrofitProductDetails.create(ProductDetailsApi::class.java) apiProductDetailsList.getProductDetails().enqueue(object : Callback<OrderDetailsModelClass> { override fun onResponse( call: Call<OrderDetailsModelClass>, response: Response<OrderDetailsModelClass> ) { orderDetailsList = response.body()?.body ?: orderDetailsList //此处可读取其他数据,但打印orderDetailsList时,productsDetalys为null } override fun onFailure(call: Call<OrderDetailsModelClass>, t: Throwable) { t.message?.let { Log.e("mesaj", it) } } }) } }
解决方案
核心错误原因
JSON中的字段是productsDetalys(首字母小写p),但你在BodyOrderDetails模型类中定义的字段是ProductsDetalys(首字母大写P)。Gson默认会严格匹配字段名的大小写,导致无法映射该字段,所以返回null。
修正步骤
1. 修正模型类字段名
将BodyOrderDetails中的ProductsDetalys改为productsDetalys,保持和JSON字段名完全一致:
data class BodyOrderDetails( // 其他字段保持不变 val productsDetalys: List<List<ProductsDetalys>>, // 其他字段保持不变 )
2. 增加空安全处理(可选但推荐)
为了避免因API返回该字段为空导致的崩溃,可以将字段声明为可空类型,并设置默认值:
data class BodyOrderDetails( // 其他字段保持不变 val productsDetalys: List<List<ProductsDetalys>>? = emptyList(), // 其他字段保持不变 )
3. 正确获取产品详情数据
在onResponse中可以这样获取productsDetalys的数据:
override fun onResponse( call: Call<OrderDetailsModelClass>, response: Response<OrderDetailsModelClass> ) { response.body()?.let { orderDetails -> orderDetailsList = orderDetails.body // 获取第一个订单的产品详情 orderDetailsList.firstOrNull()?.productsDetalys?.let { nestedList -> // 因为是嵌套列表,需要取出内层列表的元素 productsDetailsList = nestedList.flatten() // 现在productsDetailsList就是所有产品详情的列表,可以使用它做后续操作 productsDetailsList.forEach { product -> Log.d("Product", "Name: ${product.products_name}, Price: ${product.final_price}") } } } }
4. 补充Retrofit接口的@GET路径
注意你的ProductDetailsApi接口中@GET()没有指定具体路径,需要补充完整的API端点,比如:
interface ProductDetailsApi { @GET("your-api-endpoint-path") // 替换为实际的API路径 fun getProductDetails() : Call<OrderDetailsModelClass> }
内容的提问来源于stack exchange,提问作者kadir yapar
相关产品推荐
相关产品推荐

