Kotlin 数据类 |添加我自己的变量而不是 JSON 键

Posted

技术标签:

【中文标题】Kotlin 数据类 |添加我自己的变量而不是 JSON 键【英文标题】:Kotlin data class | add my own variables other than JSON keys 【发布时间】:2018-11-04 11:07:58 【问题描述】:

我正在为我的 andorid 应用程序使用改造和 kotlin。

对于我的一个 API,我有以下数据类

class Set(val set_id: Long, val tickets: List<Ticket>, val timer: Int) 
class Ticket(val ticket_id: Long, val rows: List<Row>) 
class Row(val row_id: Long, val row_numbers: List<Int>) 

示例 JSON 数据


  "set_id": 60942,
  "tickets": [
    
      "ticket_id": 304706,
      "rows": [
        
          "row_id": 914116,
          "row_numbers": [
            0,
            11,
            21,
            0,
            42,
            52,
            0,
            76,
            85
          ]
        
      ]
    
  ],
  "timer": 12

Set 类包含Ticket 的列表,每张票都有Row 的列表

我的 JSON 对象只包含这些值,直到这里它都可以正常工作。改造映射也在起作用。

问题: 我想为Ticket 类添加我自己的布尔字段/变量isPlaying,稍后将在应用程序中更新。但是,这个字段应该默认设置为true。

所以我试过了

class Ticket(val ticket_id: Long, val rows: List<Row>, var isPlaying: Boolean = true) 

还有这个

class Ticket(val ticket_id: Long, val rows: List<Row>) 
    var isPlaying: Boolean = true

注意:JSON 没有 isPlaying 键,我只希望它用于应用逻辑。

两者都不起作用,isPlaying 总是显示false。我希望它默认为true

请帮帮我。谢谢!

【问题讨论】:

如果您需要后期处理,您可以按照medium.com/@elye.project/…的建议将值设置为 true @Raghunandan 我去看看 【参考方案1】:

由于下面使用的解析库,当对象通过改造实例化时,默认参数在数据类中不起作用,这可能会在不调用构造函数的情况下创建对象。例如Gson 使用sun.misc.Unsafe 来创建对象。

您可以做的是为具有默认值的字段添加支持属性:

class Ticket(
    val ticket_id: Long, 
    val rows: List<Row>, 
    private var _isPlaying: Boolean? = true
) 
    var isPlaying
        get() = _isPlaying ?: true
        set(value) 
            _isPlaying = value
        

【讨论】:

接受!你很快。 澄清一下——Gson 不使用反射,它使用sun.misc.Unsafe 来减少反射开销。第二件事作者提到属性应该稍后更新,这是只读属性不可能的,可能应该从val更改为var @hluhovskyi 感谢您的澄清,我已经更新了我的答案 响应中是否需要 _isPlaying? 它是否也适用于 kotlin data class?我试过但没有运气:(【参考方案2】:

问题的根源在于 GSON 创建对象不是通过构造函数调用,而是通过 Unsafe 人员。因此,它会导致诸如空安全或属性初始化之类的破坏。

我知道如何解决您的情况的唯一方法如下:

class Ticket(val ticket_id: Long, val rows: List<Row>) 
    private var _isPlaying: Boolean? = null
    var isPlaying: Boolean
        get() = _isPlaying ?: true // <-- default value
        set(value) 
            _isPlaying = value
        

这里我们创建一个支持属性_isPlaying,它将被 GSON 初始化为 null。接下来,我们为公共属性添加自定义 getter 和 setter,如果 _isPlaying 为空,它们会检查每个调用的方法。如果是这样,它会返回您的默认值。否则,它返回存储在_isPlaying中的值

是的,它看起来很丑。否则,您应该考虑使用另一个 json 库,例如 Jackson,据我所知它很好地支持 Kotlin。

【讨论】:

非常感谢。解决方法起到了神奇的作用。但需要一些编辑。 var isPlaying: Boolean 不是必需的 通过您建议的编辑,您可以公开可为空的字段,以防它真的没有。当然你可以使用field关键字,但是你的模型公共界面会变得更加嘈杂。 是的,但是 android 会显示警告并建议将其更改为字段。 这只是 lint 警告,它不知道你的意图,显然你不应该到处遵循这样的警告。对我来说,创建清晰的商业模式比 Android lint 发出的警告要重要得多。 私有变量_isPlaying:布尔值? =空;保持它为空对我有用【参考方案3】:

使用 GsonBuilder setFeildNamePolicy

 val gson = GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create()


        val info = gson.fromJson(json, Account::class.java)


data class Account(
        @SerializedName("user_name") var userName: String = "",
        @SerializedName("ticket_id")  var ticketId: String = "",
        @SerializedName("row_id")  var rowId: String = "")


【讨论】:

我没有得到这个,我不想手动将 json 字符串映射到对象。改造就可以了 在改造中你可以在改造初始化器中添加 .addConverterFactory(GsonConverterFactory.create(gson)) 我想你没有得到我的问题。我想将自己的变量添加到数据类中。 可以添加有问题的json数据吗 添加了示例 json 数据

以上是关于Kotlin 数据类 |添加我自己的变量而不是 JSON 键的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Kotlin 类默认是 final 而不是 open?

暴露属性和 Kotlin 数据类的接口

在 kotlin 中的 requestLocationUpdates 之后移动标记而不是添加它

Kotlin 类的 Android 单元测试因“找不到符号类...”而失败

外部键盘导致换行而不是 Android 上的搜索 - Kotlin

将数据类的对象添加到 Kotlin 的 Firestore 时如何添加 Firebase 时间戳?