Reputation: 9
I'm trying to make a replica chat app and I have a list that I need populated into the recyclerview. I'm getting data from firebase realtime database and every time I receive or actually send a message, All the previous item(messages) plus the new one are repopulated/duplicated into the recycler view.
What I have tried
I have tried using .cleaar()
method on my list before adding a new item to the list but now all other items in the recycler view disappear
here's my adapter
public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int MSG_TYPE_LEFT = 0;
public static final int MSG_TYPE_RIGHT = 1;
FirebaseUser firebaseUser;
private Context ctx;
private List<Messages> msgsR, msgsS;//ignore unused
private ArrayList<Messages> dataSet;
public MessageAdapter(Context context) {
this.ctx = context;
this.dataSet = new ArrayList<>();
//this.msgsR = messagesReceived;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == Messages.SENT_TYPE) {
View view = LayoutInflater.from(ctx).inflate(R.layout.message_item_right, parent, false);
return new ViewHolderS(view);
}
if (viewType == Messages.RECEIVED_TYPE) {
View view = LayoutInflater.from(ctx).inflate(R.layout.message_item_left, parent, false);
return new ViewHolderR(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
Messages object = dataSet.get(position);
if (object != null) {
switch (object.type) {
case Messages.RECEIVED_TYPE:
((ViewHolderR) holder).populate(object, position);
break;
case Messages.SENT_TYPE:
((ViewHolderS) holder).populate(object, position);
break;
}
}
}
//recceives messages object to populate into list
//it does not matter where i put the .clear() method, after or below dataset.add() its still undesireable
public void addMessageSent(Messages messages){
dataSet.clear();
dataSet.add(messages);
// notifyItemInserted(dataSet.size()-1);
//notifyItemRangeChanged(dataSet.size()-1, dataSet.size());
}
@Override
public int getItemCount() {
return dataSet.size();
}
// sent messages are handled here
public static class ViewHolderS extends RecyclerView.ViewHolder {
public TextView msg, time;
public LinearLayout layout;
public ViewHolderS(@NonNull View itemView) {
super(itemView);
layout = itemView.findViewById(R.id.cont);
msg = itemView.findViewById(R.id.send_msg);
time = itemView.findViewById(R.id.time);
}
private void populate(Messages messages, int position) {
msg.setText(messages.getMessage());
msg.setPadding(6, 4, 18, 4);
msg.setMinWidth(100);
msg.setMaxWidth(400);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) msg.getLayoutParams();
layoutParams.gravity = Gravity.START;
layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;
layoutParams.topMargin = layoutParams.bottomMargin = layoutParams.rightMargin = 10;
layoutParams.leftMargin = 20;
msg.setLayoutParams(layoutParams);
time.setText(messages.getTime());
}
}
@Override
public int getItemViewType(int position) {
switch (dataSet.get(position).type) {
case 0:
return Messages.SENT_TYPE;
case 1:
return Messages.RECEIVED_TYPE;
default:
return -1;
}
}
// received messages are handled here
private class ViewHolderR extends ViewHolderS {
public TextView msg, time;
public LinearLayout layout;
public ViewHolderR(@NonNull View itemView) {
super(itemView);
layout = itemView.findViewById(R.id.cont);
msg = itemView.findViewById(R.id.send_msg);
time = itemView.findViewById(R.id.time);
}
private void populate(Messages messages, int position) {
msg.setText(messages.getMessage());
msg.setPadding(6, 4, 18, 4);
msg.setMinWidth(100);
msg.setMaxWidth(400);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) msg.getLayoutParams();
layoutParams.gravity = Gravity.START;
layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;
layoutParams.topMargin = layoutParams.bottomMargin = layoutParams.rightMargin = 10;
layoutParams.leftMargin = 20;
msg.setLayoutParams(layoutParams);
time.setText(messages.getTime());
}
}
}
and here's my data model
public class Messages {
private String message;
public static final int SENT_TYPE=0;
public static final int RECEIVED_TYPE=1;
public static final int AUDIO_TYPE=2;
private long time;
public int type;
private String id;
private String receiver;
public Messages(String message,long time, String sender,String receiver, int type) {
this.message = message;
this.time = time;
this.id = sender;
this.type = type;
this.receiver = receiver;
}
public Messages() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTime() {
SimpleDateFormat output = new SimpleDateFormat("HH:mm", Locale.getDefault());
return output.format(new Date(time));
}
public void setTime(long time) {
this.time = time;
}
public String getSender() {
return id;
}
public void setSender(String sender) {
this.id = sender;
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
}
and below is activity class where I set the adapter and fill the list
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
list= new ArrayList();
messageAdapter = new MessageAdapter(PersonChatActivity.this);
recyclerView.setAdapter(messageAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
if (Objects.requireNonNull(recyclerView.getAdapter()).getItemCount() > 0) {
recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount());
}
//get sent messages from firebase
private void getmessages() {
DatabaseReference reference = database.getReference("Chats");
reference.keepSynced(true);
reference.child(senderId).child(receiver).push();
reference.child(senderId).child(receiver).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
messageSent.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
if (dataSnapshot.getValue() != null) {
String message = (String) dataSnapshot.child("message").getValue();
long time = (Long) dataSnapshot.child("time").getValue();
String senderId = (String) dataSnapshot.child("id").getValue();
String receiverId = (String) dataSnapshot.child("receiver").getValue();
assert firebaseUser != null;
String user = firebaseUser.getUid();
Messages msg = new Messages(message, time, senderId, receiverId,Messages.SENT_TYPE);
String Uid = msg.getSender();
if (!Uid.isEmpty() && Uid.equals(user)) {
//pass the new message object to messages adapter to fill the list
messageAdapter.addMessageSent(msg);
}
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
EDIT UPDATE
As suggested I have made the necessary changes and code works like magic I wont update the right changes into the question in case someone makes the same mistake as I have plus the comment marked as answer basically highlights the correct changes,,
NEW PROBLEM
The new problem is, on adding object message to the addMessagesent()
previously populated recyclerview items get replaced by the new data.
to make it easy, on receiving a new message, all the previous visible sent messagees disappear and are replaced by the new received messages
here is my getmessageReceived()
method
DatabaseReference reference = database.getReference("Chats");
reference.keepSynced(true);
reference.child(receiver).child(senderId).push();
reference.child(receiver).child(senderId).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
messageReceived.clear();
messageAdapter.clearAllMessage();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
if (dataSnapshot.getValue() != null) {
String message = (String) dataSnapshot.child("message").getValue();
long time = (Long) dataSnapshot.child("time").getValue();
String senderId = (String) dataSnapshot.child("id").getValue();
String receiverId = (String) dataSnapshot.child("receiver").getValue();
assert firebaseUser != null;
String user = firebaseUser.getUid();
Messages msg = new Messages(message, time, senderId, receiverId,Messages.RECEIVED_TYPE);
String Uid = msg.getReceiver();
if (!Uid.isEmpty() && Uid.equals(user)) {
messageAdapter.addMessageSent(msg);
messageAdapter.notifyDataSetChanged();
}
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
Upvotes: -1
Views: 56
Reputation: 7220
You should not clear the data set in the addMessageSent()
just add new item to data set as shown below
public void addMessageSent(Messages messages){
dataSet.add(messages);
}
and create a new method to clear the dataset in your adapter
public void clearAllMessage(){
dataSet.clear();
}
And in getmessages() call clearAllMessage() like this
private void getmessages() {
DatabaseReference reference = database.getReference("Chats");
reference.keepSynced(true);
reference.child(senderId).child(receiver).push();
reference.child(senderId).child(receiver).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
messageSent.clear();
clearAllMessage();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
if (dataSnapshot.getValue() != null) {
String message = (String) dataSnapshot.child("message").getValue();
long time = (Long) dataSnapshot.child("time").getValue();
String senderId = (String) dataSnapshot.child("id").getValue();
String receiverId = (String) dataSnapshot.child("receiver").getValue();
assert firebaseUser != null;
String user = firebaseUser.getUid();
Messages msg = new Messages(message, time, senderId, receiverId,Messages.SENT_TYPE);
String Uid = msg.getSender();
if (!Uid.isEmpty() && Uid.equals(user)) {
//pass the new message object to messages adapter to fill the list
messageAdapter.addMessageSent(msg);
messageAdapter.notifyDataSetChanged(); // Call this also
}
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
Upvotes: 1