【问题标题】:Kotlin No setter/field for Value found on class Object warning for FirebaseKotlin 在 Firebase 的类对象警告中找不到值的设置器/字段
【发布时间】:2019-08-10 07:40:16
【问题描述】:

我正在尝试从我的 Firebase 数据库中获取 ChatMessage 数据类中的所有消息数据。在日志中,我可以看到数据确实是在我的快照中提取的,但它没有被分配给数据类中的变量。我是 Kotlin 和 Firebase 的新手,所以我不太明白为什么会这样?

在我搜索了一些日志后,我发现我收到了这个警告:

W/ClassMapper:在类 com.idiotboxes.socialowl.models.ChatMessage 上找不到 -Llk34LtqGPJ3bwPrYRi 的设置器/字段

在这里搜索了这个错误并发现它确实是一个非常常见的问题。但我的问题是,没有一个解决方案具有像我这样的数据类格式。

我知道警告是说我需要在我的数据类中设置 getter 和 setter,但我对 Kotlin 还很陌生,我不知道如何在我的数据类中实现 getter-setter。

这是我的数据类 ChatMessage 的样子:

package com.idiotboxes.socialowl.models

data class ChatMessage(val messageID: String, val fromID: String, val toID: 
String,val message: String, val timeStamp: Long){

    //No argument constructor
    constructor(): this("","","","",-1)
}

我的 Firebase 数据库节点如下所示: Database Structure

编辑:这里有额外的代码可以帮助您了解问题可能出在哪里

我的回调接口

interface FirebaseCallback {

    fun onCallback(latestMessage: ChatMessage)

}

我的函数从 Firebase 读取数据

private fun readFirebaseData(firebaseCallback: FirebaseCallback){
    //Signed In user's ID
    val fromID = FirebaseAuth.getInstance().uid
    Log.w(TAG, "from ID is: $fromID (Currently Signed-In user)")

    //Get Database Reference
    val msgRef = FirebaseDatabase.getInstance().getReference("/Latest-messages/$fromID"/* Reference to current user's database entry */)

    //Set a Listener for new messages
    msgRef.addChildEventListener(object: ChildEventListener {
        //adds new row when someone messages you for the first time, i.e. New Child is Added
        override fun onChildAdded(p0: DataSnapshot, p1: String?) {
            Log.w(TAG, "Snapshot captured from Firebase Database is: $p0")
            //Convert snapshot to messages
            //val latestMessage = p0.getValue(ChatMessage::class.java) ?: return
            val callbackData: ChatMessage = p0.getValue(ChatMessage::class.java) ?: return
            //TODO Implement Callback
            firebaseCallback.onCallback(callbackData)
        }

        //Updates existing rows latest messages when user receives new message i.e. Latest Message child is Changed.
        override fun onChildChanged(p0: DataSnapshot, p1: String?) {
            val latestMessage: ChatMessage = p0.getValue(ChatMessage::class.java) ?: return//If Null then return

            //Update the Existing row with new message
            latestMessagesHashMap[p0.key!!] = latestMessage
            updateRecyclerView()

        }
    --Some redundant methods of ChildEventListener--
    })
    latest_messages_recycler_view.adapter = adapter
    //Recycler View Bottom Line Border
    latest_messages_recycler_view.addItemDecoration(DividerItemDecoration(activity, DividerItemDecoration.VERTICAL))
}

我尝试从回调中检索数据的函数

private fun showLatestMessages(){

readFirebaseData(object : FirebaseCallback{
        override fun onCallback(latestMessage: ChatMessage) {
            //TODO latestMessage is  not null. But blank values are  being filled  in the Chat Message model class
            Log.w(TAG, "NotNull latestMessage values are fromID: ${latestMessage.fromID} toID: ${latestMessage.toID} Typed Message: ${latestMessage.message} TimeStamp: ${latestMessage.timeStamp}")

            //Add the new message row
            adapter.add(LatestMessagesItems(latestMessage, context ?: return))
        }
    })

    //Set OnClick Listener on Recycler View Items
    adapter.setOnItemClickListener { item, view ->
        //Grab the User details from the item that is clicked.
        val userItem = item as LatestMessagesItems

        //Start Chat Activity with the clicked User
        val startChat = Intent(activity, ChatActivity::class.java)
        startChat.putExtra(USER_KEY, userItem.recipientUser)
        startActivity(startChat)
    }
}

private fun updateRecyclerView(){
    //Clear existing rows
    adapter.clear()
    //Fetch all Latest Messages from HashMap
    latestMessagesHashMap.values.forEach {
        adapter.add(LatestMessagesItems(it, context?: return))
    }
}

我的回收站视图的消息项

class LatestMessagesItems(val latestMessage: ChatMessage, val ctx: Context): Item<ViewHolder>(){

lateinit var recipientUser: User

override fun getLayout(): Int {
    return R.layout.latest_message_row
}

override fun bind(viewHolder: ViewHolder, position: Int) {

    Log.w(TAG, "Fetched latest Message is: $latestMessage")
    //Null Check
    val recipientID: String? = if (latestMessage.fromID == FirebaseAuth.getInstance().uid) {
        latestMessage.toID
    } else {
        latestMessage.fromID
    }

    //Fetch the recipient user details
    val fetchRef = FirebaseDatabase.getInstance().getReference("/users/$recipientID")
    fetchRef.addListenerForSingleValueEvent(object: ValueEventListener{
        override fun onDataChange(p0: DataSnapshot) {
            Log.w(TAG, "Fetched Recipient ID is: $recipientID")
            //Fetch user details in User model class
            recipientUser = p0.getValue(User::class.java) ?: return
            Log.w(TAG, "Fetched Recipient User Name is: ${recipientUser.username}")

            //Fill the User Details
            viewHolder.itemView.recipient_username.text = recipientUser.username //Username
            Glide.with(ctx).load(recipientUser.profileImage).into(viewHolder.itemView.recipient_profile_image) //Profile Pic
        }

            override fun onCancelled(p0: DatabaseError) {

            }
        })

        //Latest Message Received
        viewHolder.itemView.latest_received_message.text = latestMessage.message
    }
}

最后我根据此处发布的一些建议更新了我的模型类。 ChatMessage.kt

package com.idiotboxes.socialowl.models

data class ChatMessage(var messageID: String? = null, var fromID: String? = null , var toID: String? = null ,var message: String? = null , var timeStamp: Long? = null){
    //No argument constructor
    constructor(): this("","","","",-1)
}

然而,问题仍然存在。

【问题讨论】:

  • 我不知道 Firebase,但在有更多知识渊博的人出现之前……您可以尝试开设课程 open。一些框架(如 Spring)依赖于在运行时创建子类,以便它们可以添加功能。 (事实上​​,有一个 Maven 插件可以自动打开所有相关的类。)这里让我怀疑的是,你的类显然没有名为 -Llk34LtqGPJ3bwPrYRi 的字段...
  • 请编辑问题以显示失败的数据库的代码。这是第一个问题 - 您正在尝试反序列化看起来不像 User 对象的 DataSnapshot。您还没有遇到的第二个问题是,您的数据类属性必须全部为 var 并具有默认值,以便 Kotlin 为每个属性生成 setter 方法。
  • @gidds @DougStevenson 我已经用您可以查看的更多相关代码更新了我的问题。关于-Llk34LtqGPJ3bwPrYRi 的值是什么,它是正在更新到数据库结构中的最新消息的键。如果您再次查看我在问题中发布的数据库屏幕截图,您会看到我已将键的值设置为字段messageID,该字段确实存在于我的模型中。 i> 所以请再看看我的代码。谢谢。
  • 是的,因此,您需要比现在更深入地研究该子快照。您必须首先在快照位置迭代子项,然后将它们加载到 User 对象中。
  • @DougStevenson 正如我之前提到的,我是 Kotlin 和 Firebase 的新手。从您的建议中我可以理解,我应该直接获取对我的 -Llk34LtqGPJ3bwPrYRi 节点的引用,因此它将把它里面的所有子节点的值都放到我的 Model 类中,对吗?事情是 idk 如何将我的数据库引用路径直接获取到密钥。因为它涉及遍历两个唯一生成的用户 ID 和消息的唯一键。您能否查看我的代码并建议我应该在哪里以及如何更改数据库引用以便它直接到达关键节点?

标签: firebase-realtime-database kotlin getter-setter data-class


【解决方案1】:

我不能肯定地说是这样,但我认为你应该写到 variables (var),而不是 values (val)。

这是因为 Kotlin 会自动为被认为是可变的 var 生成 getter/setter,而不会为被认为是不可变的 val 生成 getter/setter。

private vars 也会发生同样的情况,因为 Kotlin 不会在本地范围之外为它们提供 getter/setter(例如让 Firebase 访问它们)。

【讨论】:

    猜你喜欢
    • 2018-07-25
    • 2020-07-15
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多