【问题标题】:Data class dynamically change serializable name数据类动态改变可序列化名称
【发布时间】:2021-07-14 13:00:43
【问题描述】:

我刚开始实习,我被要求使用 Retrofit 等进行一些基本实现。我有一个 Json 响应,它的键值会根据请求参数而变化,我不知道如何获取该值键。

像这样:

{
  "status": {
    /*Some other unimportant JSON here */
  },
  "data": {
    "KEY_THAT_CHANGES": {
      "id": 74,
      /* more JSON here */
    }
  }
}

我想有多种解决方案可以获取该密钥:通过索引(因为它始终是“数据”中的第一个密钥)或通过将可序列化名称作为参数传递(因为我已经拥有密钥)或使用自定义反序列化类。

请求函数:Json中的key和symbol参数是一样的

@Headers(API_KEY)
    @GET("v1/cryptocurrency/info")
    fun getCoin(@Query("symbol")symbol: String):Call<CoinInfo>

我有以下数据类来保存数据:

data class CoinInfo(
    val `data`: Data,
    val status: Status
)


data class Status(
    val credit_count: Int,
    val elapsed: Int,
    val error_code: Int,
    val error_message: Any,
    val notice: Any,
    val timestamp: String
)


data class Data(
    val Coin: Coin //Here is the problem, the key is dynamically changing
)


data class Coin(
    val category: String,
    val date_added: String,
    val description: String,
    val id: Int,
    val is_hidden: Int,
    val logo: String,
    val name: String,
    val notice: String,
    val platform: Any,
    val slug: String,
    val subreddit: String,
    val symbol: String,
    @SerializedName("tag-groups")
    val tag_groups: List<String>,
    @SerializedName("tag-names")
    val tag_names: List<String>,
    val tags: List<String>,
    val twitter_username: String,
    val urls: Urls
)

请求通话

val api = Retrofit.Builder()
             .baseUrl(BASE_URL)
             .addConverterFactory(GsonConverterFactory.create())
             .build()
             .create(getRequest::class.java)

GlobalScope.launch(Dispatchers.IO) {
     val response = api.getCoin(coin.symbol).awaitResponse() // coin.symbol is also the key of the JSON
         
            if(response.isSuccessful){
                val data = response.body()!!

                withContext(Dispatchers.Main){
                    // TO DO
                }
            }
        }

我找不到任何有用的解决方案,大约 36 小时前我才开始学习 Kotlin。

【问题讨论】:

  • 考虑使用java.util.Map

标签: android kotlin gson retrofit


【解决方案1】:

假设您的 api 提供 CoinBill,那么您可以这样建模:

data class Data(
    val Coin: Coin?,
    val bill: Bill?
)

如果我没记错的话,gson 只会将缺失的键设置为 null,因此您可以稍后检查实际交付的内容。 当您拥有已知数量且彼此之间存在显着差异的对象时,这是一个可接受的解决方案。


如果你的硬币对象在结构上没有区别或者你有无数个名字,那么你很可能应该改变你的 api 并做某事。类似这样:

data class Coin(
    val myCoinIdentifier: String, /* 1-ct-coin, 2-ct-coin, 5-ct-coin...  */
    ...
)

关于风格的一句话:

  • 不鼓励调用类Data,因为它是您可以给出的最通用的描述。此外,data 可能是保留的,请参阅data class。相反,使用实际有用的名称
  • 变量名称应以小写字母开头,以区别于它们所代表的类,例如使用val coin: Coin,而不是val Coin: Coin
  • 我们不在变量名中使用下划线,而是使用驼峰式大小写,例如tagGroups,不是tag_groups
  • 您应该有充分的理由通过网络发送any,您不能进一步说明吗?
  • 你不应该需要'data'周围的单个刻度线

【讨论】:

  • 我刚刚有机会和我的实习老师谈过这个问题,他同意这是一个例外情况,最简单的解决方案是编写一个手动解析 JSON 的函数。我想这不是在使用 API 时经常发生的事情。但是感谢有关“数据”的提示,我通常不使用那个因为使用这样的词作为变量名已经足够可怕了。这是 JSON 到数据类生成器写的东西,但会改变它。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-26
  • 1970-01-01
相关资源
最近更新 更多