I'm trying to fetch all messages data inside my ChatMessage data class from my Firebase Database. In the logs, I can see that data is indeed fetched inside my Snapshot, but it isn't getting assigned to my variables in the data class. I'm new to Kotlin & Firebase, so I don't really understand why is it happening?
After I did some logs searching I found out that I have been receiving this warning:
W/ClassMapper: No setter/field for -Llk34LtqGPJ3bwPrYRi found on class com.idiotboxes.socialowl.models.ChatMessage
Did some searching for this error here & found it is a very common problem indeed. But my issue, none of the solutions have a data class format like mine.
I understand that the warning is saying I need to setup getters & setters in my data class, but I'm fairly new to Kotlin & I don't know how to implement getter-setters in my data class.
Here's how my data class ChatMessage looks like:
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)
}
Here is how my Firebase Database node looks like: Database Structure
EDIT: Here's extra code to help you understand where the problem could be
My Callback interface
interface FirebaseCallback {
fun onCallback(latestMessage: ChatMessage)
}
My function which reads the Data from 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))
}
Function where I attempt to retrieve data from my callback
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))
}
}
My messages item for my recyclerview
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
}
}
And Finally I updated my Model Class according to some of the suggestions posted here. 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)
}
Yet, the problem still persists.