Retrofit2,我如何转换具有不同对象名称但相同数据类型的响应
Retrofit2, how I can convert response with diferent object names but same data types
我有一个电话 return 不同的对象名称,在这种情况下,每个名称都是你钱包地址的哈希值,但我想对它们无动于衷,因为重要的是数据在它们内部,使用像 Gson 这样的标准转换器我无法做到这一点,有什么办法可以手动完成吗?
{
"0x1234": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 500
},
"0x1244445": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
},
"0x47851":{
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
}
}
我的存储库:
class WalletsResumeRepository(
private val service: apiService
) {
suspend fun getAddressData(listAddress: List<String>): Flow<Result<List<DetailModel>>> =
flow {
emit(Result.success(service.getWalletResume(listAddress))
}.catch { e ->
emit(Result.failure(RuntimeException("Something went wrong ${e.cause}")))
}
}
我的存储库总是陷入 NPE 的捕获场景,记住响应可以有无数的地址,所以无限的对象名称,我如何将它们视为泛型并仅将响应映射为列表?或类似的东西?
Service.kt
suspend fun getWalletResume(@Path("address") wallet: String): WalletDetailDTO
WalletDTO
data class WalletDetailDTO(
val success: Boolean,
@SerializedName("cache_last_updated")
val cacheLastUpdated: Long?,
val totalSlp: Int?
)
据我了解你的问题,这与改造无关,与 JSON 解析有关。
因为payload结构有点笨拙,建议分两步使用:
- 步骤 1. 消耗
content
success
、cache_last_updated
和 total
- 步骤 2. 添加
id
data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int)
interface apiService {
@GET("....")
fun getWalletResume( listAddress: List<String> ): Call<Map<String, DetailModel>>
}
调用 apiService.getWalletResume
的结果是 Map<String, DetailModel>
,然后您将在步骤 2 中对其进行处理。
例子
val json = """
{
"0x1234": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 500
},
"0x1244445": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
},
"0x47851": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
}
}
""".trimIndent()
data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int)
fun main() {
val gson = Gson()
val type: Type = object : TypeToken<Map<String, DetailModel>?>() {}.type
// step 1. simulates the retrofit call
val mapResult: Map<String, DetailModel> = gson.fromJson(json, type)
// step 2
val result = mapResult.map { entry -> entry.value.copy(id = entry.key) }
println(result)
// [DetailModel(id=0x1234, success=true, cache_last_updated=1642815869695, total=500), DetailModel(id=0x1244445, success=true, cache_last_updated=1642815869695, total=324), DetailModel(id=0x47851, success=true, cache_last_updated=1642815869695, total=324)]
}
在我看来,您只是在寻找 Map<String, WalletDetailDTO>
的响应类型。然后您可以简单地查看地图中的“值”以获得唯一的对象列表。
那么你的服务电话看起来像
@GET("....")
suspend fun getWalletDetails(...): Map<String, WalletDetailDTO>
然后当您使用该数据时,您将提取值:
val mapOfWalletDetails = apiService.getWalletResume(...)
val walletDetailCollection: Collection<WalletDetailDTO> = mapOfWalletDetails.values()
如果您只是想忽略原始地图中的键,那么这个最终 walletDetailCollection
似乎就是您要找的东西。
我有一个电话 return 不同的对象名称,在这种情况下,每个名称都是你钱包地址的哈希值,但我想对它们无动于衷,因为重要的是数据在它们内部,使用像 Gson 这样的标准转换器我无法做到这一点,有什么办法可以手动完成吗?
{
"0x1234": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 500
},
"0x1244445": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
},
"0x47851":{
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
}
}
我的存储库:
class WalletsResumeRepository(
private val service: apiService
) {
suspend fun getAddressData(listAddress: List<String>): Flow<Result<List<DetailModel>>> =
flow {
emit(Result.success(service.getWalletResume(listAddress))
}.catch { e ->
emit(Result.failure(RuntimeException("Something went wrong ${e.cause}")))
}
}
我的存储库总是陷入 NPE 的捕获场景,记住响应可以有无数的地址,所以无限的对象名称,我如何将它们视为泛型并仅将响应映射为列表?或类似的东西?
Service.kt
suspend fun getWalletResume(@Path("address") wallet: String): WalletDetailDTO
WalletDTO
data class WalletDetailDTO(
val success: Boolean,
@SerializedName("cache_last_updated")
val cacheLastUpdated: Long?,
val totalSlp: Int?
)
据我了解你的问题,这与改造无关,与 JSON 解析有关。 因为payload结构有点笨拙,建议分两步使用:
- 步骤 1. 消耗
content
success
、cache_last_updated
和total
- 步骤 2. 添加
id
data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int)
interface apiService {
@GET("....")
fun getWalletResume( listAddress: List<String> ): Call<Map<String, DetailModel>>
}
调用 apiService.getWalletResume
的结果是 Map<String, DetailModel>
,然后您将在步骤 2 中对其进行处理。
例子
val json = """
{
"0x1234": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 500
},
"0x1244445": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
},
"0x47851": {
"success": true,
"cache_last_updated": 1642815869695,
"total": 324
}
}
""".trimIndent()
data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int)
fun main() {
val gson = Gson()
val type: Type = object : TypeToken<Map<String, DetailModel>?>() {}.type
// step 1. simulates the retrofit call
val mapResult: Map<String, DetailModel> = gson.fromJson(json, type)
// step 2
val result = mapResult.map { entry -> entry.value.copy(id = entry.key) }
println(result)
// [DetailModel(id=0x1234, success=true, cache_last_updated=1642815869695, total=500), DetailModel(id=0x1244445, success=true, cache_last_updated=1642815869695, total=324), DetailModel(id=0x47851, success=true, cache_last_updated=1642815869695, total=324)]
}
在我看来,您只是在寻找 Map<String, WalletDetailDTO>
的响应类型。然后您可以简单地查看地图中的“值”以获得唯一的对象列表。
那么你的服务电话看起来像
@GET("....")
suspend fun getWalletDetails(...): Map<String, WalletDetailDTO>
然后当您使用该数据时,您将提取值:
val mapOfWalletDetails = apiService.getWalletResume(...)
val walletDetailCollection: Collection<WalletDetailDTO> = mapOfWalletDetails.values()
如果您只是想忽略原始地图中的键,那么这个最终 walletDetailCollection
似乎就是您要找的东西。