Reputation: 2544
I am developing a chat app by using firebase realtime database. I am using FirebaseRecyclerAdapter to display messages. But the thing is on scrolling, messages get duplicated and out of order.
Here is my implementation:
public class FirebaseChatActivity extends AppCompatActivity {
private String messageSenderId;
private String messageReceiverId;
private FirebaseRecyclerAdapter<ChatMessage, MessageViewHolder> firebaseRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_firebase_chat);
RecyclerView recyclerView = findViewById(R.id.rv_firebase_chat_activity);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
messageSenderId = "eoSU5m7PyucyC9h30JfHhV6S8Av2";
messageReceiverId = "ZOqofCid0XN5ovIAj1mXhRYxdnO2";
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("messages").child(messageSenderId).child(messageReceiverId);
FirebaseRecyclerOptions<ChatMessage> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, ChatMessage.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<ChatMessage, MessageViewHolder>(firebaseRecyclerOptions) {
@Override
protected void onBindViewHolder(@NonNull MessageViewHolder messageViewHolder, int position, @NonNull ChatMessage message) {
if (message.getMessageType().equals("text")) {
messageViewHolder.showMessage.setText(message.getMessageText());
} else if (message.getMessageType().equals("image")) {
try {
Glide.with(getApplicationContext())
.load(message.getPhotoUrl())
.placeholder(R.drawable.no_image2)
.error(R.drawable.image_1)
.into(messageViewHolder.photoImageView);
} catch (Exception e) {
Log.d("MessageAdapterLog", e.toString());
}
}
}
@Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
android.view.View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_item_right, parent, false);
return new MessageViewHolder(view);
}
};
recyclerView.setAdapter(firebaseRecyclerAdapter);
}
private class MessageViewHolder extends RecyclerView.ViewHolder {
public TextView showMessage;
public ImageView photoImageView;
public MessageViewHolder(@NonNull android.view.View itemView) {
super(itemView);
showMessage = itemView.findViewById(R.id.show_message);
photoImageView = itemView.findViewById(R.id.photo_image_view);
}
}
@Override
protected void onStart() {
super.onStart();
firebaseRecyclerAdapter.startListening();
}
@Override
protected void onStop() {
super.onStop();
if (firebaseRecyclerAdapter!= null) {
firebaseRecyclerAdapter.stopListening();
}
}
}
I have tried many different solutions e.g set as mentioned here as well as .addChildEventListener
(completely different implementation) but unable to solve the issue.
Full Activity code as well as database structure is attached. Kindly let me know what I am doing wrong.
Thanks
Upvotes: 1
Views: 290
Reputation: 13129
The problem is that everytime you scroll, to make a new item visible again it will run the code inside your onBindViewHolder to inflate that view and rebind it.
if (message.getMessageType().equals("text")) {
messageViewHolder.showMessage.setText(message.getMessageText());
} else if (message.getMessageType().equals("image")) {
try {
Glide.with(getApplicationContext())
.load(message.getPhotoUrl())
.placeholder(R.drawable.no_image2)
.error(R.drawable.image_1)
.into(messageViewHolder.photoImageView);
} catch (Exception e) {
Log.d("MessageAdapterLog", e.toString());
}
}
}
to solve this problem you will need to override two methods inside your adapter
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
Upvotes: 3