0

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)

}

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Tommy -
  • 53
  • 9
  • 1
    Please edit your question and add the code that produces that error. Please also add your database structure as a JSON file. You can simply get it by clicking the Export JSON in the overflow menu (⠇) in your [Firebase Console](https://console.firebase.google.com/u/0/project/_/database/data). – Alex Mamo Jul 19 '22 at 13:09
  • The problem seems in reading your message DB, not due to sending. Add your message reading part code so that other's can understand the problem and give solution. – Ahsan Ullah Rasel Jul 19 '22 at 13:25
  • Hi @AhsanUllahRasel yes, the problem with this situation is, previously, sending messages was fine until there was one time an emoji was sent and it crashed. After that, whenever a normal text message was sent, the app will show this error all the time and crash. I think this has nothing to do with the code, but more on Firebase side. Maybe the something was changed there (maybe the data type?) when it received an emoji but not sure what was changed and where to fix it. – Tommy - Jul 19 '22 at 13:46
  • Hi @AlexMamo yep, JSON file provided – Tommy - Jul 19 '22 at 13:57
  • So is this the line `val chatMessage = snapshot.getValue(ChatMessage::class.java)` that produces the error? – Alex Mamo Jul 19 '22 at 14:30
  • Hi @AlexMamo , the code for ChatMessage has also been provided. Thanks :) – Tommy - Jul 19 '22 at 14:36
  • I was just asking if that line `chatMessage = snapshot.getValue(ChatMessage::class.java)` produces the error? – Alex Mamo Jul 19 '22 at 14:39
  • Maybe yes @AlexMamo – Tommy - Jul 19 '22 at 14:44
  • To be able to help, you need to be sure about the error. – Alex Mamo Jul 19 '22 at 15:22
  • Hi @AlexMamo yes I have checked the logcat but Android Studio only provide the error that is shown above and does not tell which line where the error occurs. – Tommy - Jul 19 '22 at 15:36
  • Try roughly `getValue(String)` instead and print the string to see what it looks like. – hellowill89 Jul 20 '22 at 04:28
  • I think I got the issue. So to be sure, you only want to read a **single** chat message that exists at this reference, `"/pesan-pengguna/$fromId/$toId"`, right? Please respond with @AlexMamo – Alex Mamo Jul 20 '22 at 05:01
  • Hi @AlexMamo I have inspect the code by running it while deleting some lines, it seems the app crash when this code is included `chatMessage = snapshot.getValue(ChatMessage::class.java)` so it might be that code is the problem and all the messages from `"/pesan-pengguna/$fromId/$toId"` need to be read. – Tommy - Jul 20 '22 at 07:16
  • Hi @hellowill89 I cannot use only string because there are long too and need to declare all children of the nodes. – Tommy - Jul 20 '22 at 07:29
  • Hi @AlexMamo there is also one time I sent a message with a space in the beginning that lead to this crash, for example: `" Test"`. Does it have anything to do with this issue? There is no changes with the code before and after this happen. Also is there any issue with the JSON DB or the code above? – Tommy - Jul 20 '22 at 07:37
  • Can you please respond to my last comment? Spaces added before text do not crash the app. – Alex Mamo Jul 20 '22 at 07:52
  • Hi @AlexMamo Ideally, all messages with the same fromId need to be read, but at this point, even a single message would be great. – Tommy - Jul 20 '22 at 07:57
  • Ok, I'll write you an answer that will help you read a message. – Alex Mamo Jul 20 '22 at 07:59

1 Answers1

0

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.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hi Alex, your solution works well, but I wish when I open a chatting activity, I could see all my messages, instead of only the latest message. But at least your solution give an insight that the error has nothing to do with Firebase. – Tommy - Jul 20 '22 at 10:01
  • It's good to hear that my solution worked. As I already mentioned in my answer, you have to create a schema where all messages exist under a direct node. For that, I recommend you check Frank's answer from the following [post](https://stackoverflow.com/questions/52410826/how-to-model-a-chat-application-on-firebase-realtime-database). So should give it a try. – Alex Mamo Jul 20 '22 at 10:08
  • If you have a hard time implementing it, please post a new question, here on StackOverflow, using its own [MCVE](https://stackoverflow.com/help/mcve), so I and other Firebase developers can help you. – Alex Mamo Jul 20 '22 at 10:08
  • 1
    Hi Alex, really glad there is someone like you on stackoverflow. From your advice, I realise there is something wrong with my schema, and after I fix my messages under a single node, it actually fix the problem!! Thanks a lot Alex, you are really helpful here!!! Cheers!! – Tommy - Jul 20 '22 at 11:41
  • You're very welcome, Tommy. – Alex Mamo Jul 20 '22 at 11:57