【问题标题】:Retrofit2, how I can convert response with diferent object names but same data typesRetrofit2,我如何转换具有不同对象名称但数据类型相同的响应
【发布时间】:2022-01-22 02:25:03
【问题描述】:

我有一个返回不同对象名称的调用,在这种情况下,每个名称都是你钱包地址的哈希值,但我想冷漠对待它们,因为重要的是它们内部的数据,使用标准像 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 的 catch 场景,记住响应可以有无数地址,因此无限的对象名称,我如何将它们视为泛型并仅将响应映射为列表?或类似的东西?

服务.kt

suspend fun getWalletResume(@Path("address") wallet: String): WalletDetailDTO

钱包DTO

data class WalletDetailDTO(
    val success: Boolean,
    @SerializedName("cache_last_updated")
    val cacheLastUpdated: Long?,
    val totalSlp: Int?
)

【问题讨论】:

  • 服务调用apiService.getWalletResume的签名是什么?
  • 你能影响 API 设计吗?使用值作为键会让你的生活变得悲惨。

标签: java android kotlin serialization retrofit2


【解决方案1】:

据我了解,这与改造无关,更多与 JSON 解析有关。 因为payload结构有点别扭,我建议你分两步使用:

  • 步骤1.使用contentsuccesscache_last_updatedtotal
  • 步骤 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&lt;String, DetailModel&gt;,然后您将在步骤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)]
}

【讨论】:

    【解决方案2】:

    在我看来,您只是在寻找Map&lt;String, WalletDetailDTO&gt; 的响应类型。然后您可以简单地查看地图中的“值”来获取唯一的对象列表。

    那么你的服务调用看起来像

    @GET("....")
    suspend fun getWalletDetails(...): Map<String, WalletDetailDTO>
    

    然后,当您使用该数据时,您会提取值:

    val mapOfWalletDetails = apiService.getWalletResume(...)
    
    val walletDetailCollection: Collection<WalletDetailDTO> = mapOfWalletDetails.values()
    

    如果您只想忽略原始地图中的键,那么最终的walletDetailCollection 似乎就是您要寻找的。​​p>

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 1970-01-01
      • 2018-05-09
      • 2016-01-25
      • 2020-01-07
      • 2021-02-12
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      相关资源
      最近更新 更多