Message Seen or Not in android Firebase

Viewed 198

I want to show if a message is seen or not in my app which is using Firebase Realtime Database. What I am able to do till now is update it on the database if the message is seen or not but while running the code the app crashes.The line of code which is producing error is if (message.getTo().equals(messageSenderID) && message.getFrom().equals(messageReceiverID)).

This is the error coming while running

com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.shakshi.Model.Message
    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.shakshi.Activity.ChatActivity$6.onChildAdded(ChatActivity.java:291)
    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.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8512)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

Isseen Listener

private void seenMessage() {

    RootRef.child("Messages").child(messageSenderID).child(messageReceiverID);

    seenlistener = RootRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {

            for (DataSnapshot ds: snapshot.getChildren()) {

                Message message = ds.getValue(Message.class);

                if (message.getTo().equals(messageSenderID) && message.getFrom().equals(messageReceiverID)) {

                    HashMap<String, Object> hashMap = new HashMap<>();
                    hashMap.put("isseen", true);
                    ds.getRef().updateChildren(hashMap);

                }

            }

        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {

        }
    });
    RootRef.addListenerForSingleValueEvent(seenlistener);

}

My Code for checking if the message is seen or not

if (position == userMessages.size() -1) {

        if (messages.getSeen()) {

            messageViewHolder.seen.setText("seen");


        } else {
            messageViewHolder.seen.setText("Delivered");
        }

    } else {
        messageViewHolder.seen.setVisibility(View.GONE);
    }

JSON file of a Database:

"Messages" : {
"OiZrWinSoGf1zjEGOsfi4QK5BOJ3" : {
  "duYQ1hm0WLYssMFacdqgsEBwS9N2" : {
    "-MhB2t4tYdyWYdgw-Lpc" : {
      "date" : "Aug 16, 2021",
      "from" : "OiZrWinSoGf1zjEGOsfi4QK5BOJ3",
      "message" : "hello",
      "messageID" : "-MhB2t4tYdyWYdgw-Lpc",
      "time" : "04:34 am",
      "to" : "duYQ1hm0WLYssMFacdqgsEBwS9N2",
      "type" : "text"
    },
    "-MhB2vrGb8kBuqklJN27" : {
      "date" : "Aug 16, 2021",
      "from" : "duYQ1hm0WLYssMFacdqgsEBwS9N2",
      "message" : "hyy\n",
      "messageID" : "-MhB2vrGb8kBuqklJN27",
      "time" : "04:34 AM",
      "to" : "OiZrWinSoGf1zjEGOsfi4QK5BOJ3",
      "type" : "text"
    },
    "-MhB30bIMAbUv_eFEdAV" : {
      "date" : "Aug 16, 2021",
      "from" : "OiZrWinSoGf1zjEGOsfi4QK5BOJ3",
      "message" : "https://firebasestorage.googleapis.com/v0/b/lets-chat-d452c.appspot.com/o/Image%20File%2F-MhB30bIMAbUv_eFEdAV.jpg?alt=media&token=8e2fd6ed-3924-453e-91f2-865163c76479",
      "messageID" : "-MhB30bIMAbUv_eFEdAV",
      "name" : "primary:DCIM/Camera/20210618_013510.jpg",
      "time" : "04:34 am",
      "to" : "duYQ1hm0WLYssMFacdqgsEBwS9N2",
      "type" : "images"
    },

} }

Model Message Class

public class Message {

private String from, message, type, to, messageID, time, date, name;
private Boolean isSeen;

public Message()
{

}

public Message(String from, String message, String type, String to, String messageID, String time, String date, String name,Boolean isSeen) {
    this.from = from;
    this.message = message;
    this.type = type;
    this.to = to;
    this.messageID = messageID;
    this.time = time;
    this.date = date;
    this.name = name;
    this.isSeen = isSeen;
}

public String getFrom() {
    return from;
}

public void setFrom(String from) {
    this.from = from;
}

public String getMessage() {
    return message;
}

public void setMessage(String message) {
    this.message = message;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public Boolean getSeen() {
    return isSeen;
}

public void setSeen(Boolean seen) {
    this.isSeen = seen;
}

public String getTo() {
    return to;
}

public void setTo(String to) {
    this.to = to;
}

public String getMessageID() {
    return messageID;
}

public void setMessageID(String messageID) {
    this.messageID = messageID;
}

public String getTime() {
    return time;
}

public void setTime(String time) {
    this.time = time;
}

public String getDate() {
    return date;
}

public void setDate(String date) {
    this.date = date;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

2 Answers

At first you apparently query for a String (assuming that these variables do hold valid values):

RootRef.child("Messages").child(messageSenderID).child(messageReceiverID);

And then you try to cast that String to com.shakshi.Model.Message with this instruction:

Message message = ds.getValue(Message.class);

What you'd probably may want to do instead... is to query for something that averagely matches the structure of class Message - which barely is the case with class String... something alike:

RootRef.child("Messages").child(messageSenderID):

You are getting the following error:

com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.shakshi.Model.Message

Because you are attaching the listener to the "RootRef". All children that exist under this reference are strings and not Message objects.

Please note that Firebase Realtime Database queries are immutable, which means that you cannot change the properties of an existing query. If you change the value by calling .child("Messages"), it becomes a new query. That's the exact same behavior as in the case of the String class. To solve this, please chain all method calls and store them in a single Query object like this:

Query query = RootRef.child("Messages").child(messageSenderID).child(messageReceiverID);
query.addListenerForSingleValueEvent(/* ... /*);
Related