Home > Enterprise >  App crash after sending message to Firebase Database?
App crash after sending message to Firebase Database?

Time:07-20

So I use Firebase Realtime Database for messaging feature and when I send a message, the following error comes out, and the app crash. Later on, the chatting activity keeps crashing, and need to delete the message on Firebase manually to be able to reopen the chatting activity.

2022-07-19 22:56:27.078 21525-21525/com.example.gesit E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.gesit, PID: 21525
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.gesit.ChatMessage
    at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(CustomClassMapper.java:436)
    at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(CustomClassMapper.java:232)
    at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(CustomClassMapper.java:80)
    at com.google.firebase.database.DataSnapshot.getValue(DataSnapshot.java:203)
    at com.example.gesit.Chatting$listenforMessages$1.onChildAdded(Chatting.kt:86)
    at com.google.firebase.database.core.ChildEventRegistration.fireEvent(ChildEventRegistration.java:79)
    at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
    at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:226)
    at android.os.Looper.loop(Looper.java:313)
    at android.app.ActivityThread.main(ActivityThread.java:8669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

Reading message code:

private fun listenforMessages() {
    val fromId = FirebaseAuth.getInstance().uid
    val toId = toUser?.uid
    val ref = FirebaseDatabase.getInstance().getReference("/pesan-pengguna/$fromId/$toId")

    ref.addChildEventListener(object : ChildEventListener {
        override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
            val chatMessage = snapshot.getValue(ChatMessage::class.java)

            if (chatMessage != null) {
                Log.d(TAG, chatMessage?.text!!)
                if (chatMessage.fromId == FirebaseAuth.getInstance().uid) {
                    val currentUser = MainScreen.currentUser
                    adapter.add(ChatItemRight(chatMessage.text, currentUser ?: return))
                } else {
                    adapter.add(ChatItemLeft(chatMessage.text, toUser!!))
                }
            }
        }

        override fun onCancelled(error: DatabaseError) {
        }

        override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
        }

        override fun onChildRemoved(snapshot: DataSnapshot) {
        }

        override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
        }

    })

}

JSON DB for messages:

{
  "pesan-pengguna": {
    "P6scAzLXLcOsDiChjMAXOgnBnar1": {
      "nrX4w334X4R4kOyXHfp6rSFPWYv1": {
        "fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
        "id": "-N7Lf8PyUg9jWKmAv6zr",
        "text": "Test 1 2 3",
        "timestamp": 1658237785,
        "toId": "P6scAzLXLcOsDiChjMAXOgnBnar1"
      }
    },
    "nrX4w334X4R4kOyXHfp6rSFPWYv1": {
      "P6scAzLXLcOsDiChjMAXOgnBnar1": {
        "fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
        "id": "-N7Lf8PyUg9jWKmAv6zr",
        "text": "Test 1 2 3",
        "timestamp": 1658237785,
        "toId": "P6scAzLXLcOsDiChjMAXOgnBnar1"
      },
      "nrX4w334X4R4kOyXHfp6rSFPWYv1": {
        "fromId": "nrX4w334X4R4kOyXHfp6rSFPWYv1",
        "id": "-N7LfGGFTKerqT3Lma8Y",
        "text": "Test 1 2 3",
        "timestamp": 1658237818,
        "toId": "nrX4w334X4R4kOyXHfp6rSFPWYv1"
      }
    }
  }
}

Code for ChatMessage:

class ChatMessage(val id: String, val text: String, val fromId: String, val toId: String, val timestamp: Long) {
constructor() : this("","","","", -1)

}

CodePudding user response:

When you're using the following reference:

val ref = FirebaseDatabase.getInstance().getReference("/pesan-pengguna/$fromId/$toId")

And when you attach a ChildEventListener on it, it means that you're trying to read all children that exist within that reference. Now, inside the onChildAdded method you're trying to convert each element into an object of type ChatMessage, which is actually not possible since the children under that node are strings, hence that error. If you want to read a ChatMessage object, please use addListenerForSingleValueEvent, as you can see in the following lines of code:

val valueEventListener = object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        val chatMessage = snapshot.getValue(ChatMessage::class.java)
        Log.d("TAG", chatMessage.text)
    }

    override fun onCancelled(error: DatabaseError) {
        Log.d("TAG", error.getMessage()) //Never ignore potential errors!
    }
}
ref.addListenerForSingleValueEvent(valueEventListener)

The result in the logcat will be:

Test 1 2 3

Always remember, that Firebase Realtime Database queries work on a flat list. The objects that you want to read must be in a fixed location under each direct child node. If you keep your actual database schema, you won't be able to read the messages that belong to a particular formId. However, this topic was covered several times before, here on StackOverflow. So you should consider creating a schema where all messages exist under a direct node.

  • Related