将Firebase数据快照反序列化为Kotlin数据类

时间:2018-06-06 14:34:28

标签: android firebase serialization kotlin data-class

您好我有一个Kotlin数据类如下

data class User (
        @get:Exclude val gUser: Boolean,
        @get:Exclude val uid: String,
        @get:PropertyName("display_name") val displayName: String,
        @get:PropertyName("email") val email: String,
        @get:PropertyName("account_picture_url") val accountPicUrl: String,
        @get:PropertyName("provider") val provider: String
)

我可以在没有问题的情况下序列化对象。但是在执行firebase查询时,我无法反序列化对象。目前,这正是我为获取数据所做的工作

_firebaseReference.child(getString(R.string.firebase_users_key)).child(user.uid)
        .setValue(user).addOnCompleteListener{
    _firebaseReference.child("users").child(user.uid)
            .addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onCancelled(p0: DatabaseError) {

        }

        override fun onDataChange(p0: DataSnapshot) {
            if (p0.exists()) {
                val userHash = p0.value as HashMap<*, *>
                var currentUser: User
                if (userHash[getString(R.string.provider_key)]
                        != getString(R.string.provider_google)) {
                    currentUser = User(false, p0.key!!, 
                            userHash["display_name"].toString(), 
                            userHash["email"].toString(),
                            userHash["account_picture_url"].toString(), 
                            userHash["provider"].toString())
                } else {
                    currentUser = User(true, p0.key!!, 
                            userHash["display_name"].toString(), 
                            userHash["email"].toString(), 
                            userHash["account_picture_url"].toString(), 
                            userHash["provider"].toString())
                }
            }
        }

    })
}

这只是我正在努力练习我的Kotlin的测试项目,但这是我想弄清楚的。

如果我完全错误,请告诉我,任何建议都将不胜感激

由于

3 个答案:

答案 0 :(得分:11)

Firebase需要一个空的构造函数才能反序列化对象:

data class User(
        @Exclude val gUser: Boolean,
        @Exclude val uid: String,
        @PropertyName("display_name") val displayName: String,
        @PropertyName("email") val email: String,
        @PropertyName("account_picture_url") val accountPicUrl: String,
        @PropertyName("provider") val provider: String
) {
    constructor() : this(false, "", "", "", "", "")
}

您可以像这样声明它并提供一些默认值以便能够调用主构造函数,或者您可以为所有参数声明默认值:

data class User (
        @Exclude val gUser: Boolean = false,
        @Exclude val uid: String = "",
        @PropertyName("display_name") val displayName: String = "",
        @PropertyName("email") val email: String = "",
        @PropertyName("account_picture_url") val accountPicUrl: String = "",
        @PropertyName("provider") val provider: String = ""
)

然后将为您创建各种构造函数,包括空构造函数。

如果序列化存在问题,可能是因为ide生成的getter和setter,请尝试使用@get和@set注释加强它们:

data class User (
        @Exclude val gUser: Boolean = false,
        @Exclude val uid: String = "",
        @set:PropertyName("display_name") 
        @get:PropertyName("display_name")
        var displayName: String = "",
        @PropertyName("email") val email: String = "",
        @set:PropertyName("account_picture_url")
        @get:PropertyName("account_picture_url")
        var accountPicUrl: String = "",
        @PropertyName("provider") val provider: String = ""
)

答案 1 :(得分:1)

我真正想要的是一个 Kotlin 数据类,它派生自这样的域模型接口

data class Dto(@PropertyName("serialized_title") val override title: String) : DomainModel

在这种情况下,DomainModel 是这样定义的

interface DomainModel { val title: String }

我的目标是从 Firestore 获取数据并获取反序列化的 Dto 对象,这些对象提供给接收 DomainModel 类型的对象的客户端。所以不幸的是,上面的这个解决方案没有奏效。我看到了使用 @get: 和 @set: Annotations 的解决方法,但我希望我的数据类属性是不可变的。在我的用例中,简单地使用 vars 是一个糟糕的设计决策。而且这个解决方案看起来很丑......

在检查了反编译的 Java 代码后,我想出了这个解决方案

data class Dto(
@field:[JvmField PropertyName("serialized_title")]
override val title: String = "") : DomainModel

反编译的 Java 代码只是使用标题作为具有 PropertyName 注释的公共最终字段。

我更喜欢这个解决方案,因为它不会违反我做出的某些设计决定......

答案 2 :(得分:0)

在 Android Studio (kotlin) 中 使用这个(只有 var 和 getter 和 setter):

  • @set:PropertyName("email") @get:PropertyName("email") var emailPerson: String = ""

这些都不行:

  • @PropertyName("email") var emailPerson: String = ""
  • @PropertyName("email") val emailPerson: String = ""
  • @get:PropertyName("email") val emailPerson: String = ""

Android Studio 4.1.2。 Gradle:com.google.firebase:firebase-database:19.6.0