【问题标题】:firebase db: models with Kotlin delegated propertiesfirebase db:具有 Kotlin 委托属性的模型
【发布时间】:2017-08-01 22:14:13
【问题描述】:

我正在使用 Kotlin 对象来处理我的 Firebase 数据库模型,如 in the guide 所述。我有很多存储为字符串的字段,但实际上是枚举,所以为了类型安全,我在模型中有枚举字段,加上一个返回 firebase 存储值的字符串委托属性(如前段时间a question I asked 中所建议的那样)。现在,如果我在代码中获取/设置字符串委托,这些字段就可以工作,但是在转换到/从数据库的 json 格式转换时,firebase 库似乎会跳过它们。

一个简单的例子:

abstract class BaseModel {
    @Exclude
    open var path: String? = null  // fails even if I delete this field!
}

class Weight() : BaseModel() {
    constructor(v: Double, u: WeightUnit) : this() {
        value = v
        unitEnum = u
    }

    var value: Double = 0.0
    @Exclude
    var unitEnum: WeightUnit = WeightUnit.KG
    var unit: String by EnumStringLowercaseConverter(WeightUnit::class.java).getDelegate(Weight::unitEnum)

}

[...]
val testWeight = Weight(7.0, "kg")
db.getReference("/valid/path/to/save/testWeight").setValue(testWeight)
            .addOnSuccessListener { r -> Log.d(LOG_TAG, "set successful") }
            .addOnFailureListener { e -> Log.e(LOG_TAG, "set error", e) }

setValue 总是给出 Permission Denied 错误,但如果我删除 unitEnum 字段并将 unit 设置为正常的 String 属性,则可以正常工作。

读取时类似:Firebase 在获取 Weight 对象时没有给出错误,但 weightUnit 字段从未设置为默认值以外的任何值。但是,如果我手动执行weight.unit = "lb"unitEnum 字段会正确返回WeightUnit.LB

我正在使用 firebase 库 v10.0.1

现在,问题:

  • 如何使委派属性与 Firebase 一起正常工作?只要满足my original question 中的点(可读、简洁和类型安全的代码),我就可以尝试对委托枚举字段使用不同的方法。
  • 有什么方法可以了解 Firebase 库如何准确将对象转换为 json 或从 json 转换对象?或者至少看到转换后的 json?也许那时我可以自己调整一些东西。不幸的是,所有与 firebase 相关的内容在 AndroidStudio 中都显示为 /* compiled code */

更新:我当然可以为每个模型添加一个 toMap() 方法,在其中我将构建一个包含 firebase 所需的所有属性的地图,但对每个模型都这样做会很烦人模型,并且只解决了保存问题,获取时仍然不会设置枚举字段。

使用 GSON 序列化时也会跳过委托的道具。那么也许有一种通用的方法可以使委托属性看起来像常规字段?

【问题讨论】:

  • GSON 不允许序列化函数,以及委托的扩展 getter/setter。一种可能的解决方案是让 unitEnum 成为一个委托,它在更新时也会更新单位字符串。 var unitEnum: WeightUnit by EnumStringUpdate(WeightUnit::class.java).getDelegate(Weight::unit)
  • ::class.java 已弃用,请使用 .javaClass

标签: android firebase firebase-realtime-database kotlin


【解决方案1】:

试试这个代码,它应该可以工作。

@get:Exclude @set:Exclude
var unitEnum: WeightUnit = WeightUnit.KG
var unit: String
    get() = unitEnum.name
    set(v) { unitEnum = WeightUnit.valueOf(v) }

【讨论】:

  • 这是显而易见的解决方案,我知道这会起作用,但请看一下我上面链接的上一个问题,关于我为什么不想这样做:) stackoverflow.com/questions/41651507/… 简而言之: (1)我的枚举字段不能像您发布的那样直接转换,(2)我有很多这些字段并且不想重复代码,(3)我有比简单枚举更复杂的字段要转换.
  • @quezak 我会坚持使用@StringDef 注释,只是讨厌枚举(:另外,考虑创建方法toMap()fromMap(),而不是使用内置的firebase 方法进行序列化/反序列化跨度>
  • 是的,我现在正在研究适合我情况的通用toMap()fromMap()。优点是模型类中没有双重字段。缺点可能是整个模型需要在读/写时进行转换,而不仅仅是枚举字段——但现在我的模型足够小,这不应该成为问题。 (无论如何,firebase 可能会进行一些处理,具有类似的复杂性)
猜你喜欢
  • 1970-01-01
  • 2015-09-02
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2013-03-08
  • 2021-10-18
  • 1970-01-01
相关资源
最近更新 更多