Search code examples
androidfirebaseandroid-recyclerviewgoogle-cloud-firestorechat

Fetching chat messages from firestore


I am making a chat section in my app, but the only problem I am facing is that whenever I enter a new message, some of the previous messages getting displayed in the recycler views get erased from the recycler view. But those messages are present in 'firestore'. They are not getting deleted from there but are getting vanished from the recycler view as soon as I enter a new message. When I restart the activity it works perfectly all messages are there.. but the problem only occurs when I enter a new message...and also when I scroll through the 'recyclerview'. Here are the codes...

This is the chatModel class :

import java.io.Serializable;
import java.util.Date;

public class chatModel implements Serializable {

 private String Message,sender,Type,id;
 private Date Time;

 public chatModel()
 {

 }

public chatModel(String Message, String sender, String type,Date Time ,String id) {
    this.Message = Message;
    this.sender = sender;
    Type = type;
    this.Time = Time;
    this.id = id;
}

public String getMessage() {
    return Message;
}

public void setMessage(String message) {
    Message = message;
}

public String getSender() {
    return sender;
}

public void setSender(String sender) {
    this.sender = sender;
}

public String getType() {
    return Type;
}

public void setType(String type) {
    Type = type;
}

public Date getTime() {
    return Time;
}

public void setTime(Date time) {
    Time = time;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

}

This is the DiscussionActivity class:

public class DiscussionActivity extends AppCompatActivity {

private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;
private FirebaseStorage mStorage;
private DatabaseReference mDatabase;

private EditText msg;
private Button sendBtn;
private ImageView addDocs;
private Uri imageUri;
private String url;

private RecyclerView mChatContainer;
private List<chatModel> chatList;
private chatAdapter adapter;
private int position=0;

String getMessage,getTitle,getDate;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_discussion);

    mAuth = FirebaseAuth.getInstance();
    mFirestore = FirebaseFirestore.getInstance();
    mStorage = FirebaseStorage.getInstance();
    mDatabase = FirebaseDatabase.getInstance().getReference();

    msg = (EditText)findViewById(R.id.textContent);
    sendBtn = (Button)findViewById(R.id.sendMsg);
    addDocs = (ImageView)findViewById(R.id.include_documents);

    getTitle = getIntent().getExtras().getString("Title");
    int getCurrentYear = Calendar.getInstance().get(Calendar.YEAR);
    int getCurrentMonth = Calendar.getInstance().get(Calendar.MONTH);
    int getCurrentDate = Calendar.getInstance().get(Calendar.DATE);
    getDate=getCurrentDate+getCurrentMonth+getCurrentYear+"";

    mChatContainer = (RecyclerView)findViewById(R.id.chatContainer);
    chatList = new ArrayList<>();

    sendBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String message = msg.getText().toString().trim();

            int random = new Random().nextInt();
            Map chat = new HashMap();
            chat.put("Message",message);
            chat.put("sender",mAuth.getCurrentUser().getUid());
            chat.put("Time",FieldValue.serverTimestamp());
            chat.put("Type","text");
            chat.put("id",String.valueOf(random));

            mFirestore.collection("Ideas").document(getTitle).collection("Discussions").add(chat).addOnCompleteListener(DiscussionActivity.this, new OnCompleteListener() {
                @Override
                public void onComplete(@NonNull Task task) {
                    if(task.isSuccessful())
                    {
                        msg.setText("");
                    }
                }
            });
        }
    });

    addDocs.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            discussionOptionsSheetDialog obj = new discussionOptionsSheetDialog();
            Bundle bundle = new Bundle();
            bundle.putString("Title",getTitle);
            bundle.putString("id",mAuth.getCurrentUser().getUid());
            obj.setArguments(bundle);
            obj.show(getSupportFragmentManager(),"discussionOptionsBottomSheet");
        }
    });


    adapter = new chatAdapter(chatList,getTitle);
       Query first = mFirestore.collection("Ideas").document(getTitle).collection("Discussions").orderBy("Time");
    first.addSnapshotListener(DiscussionActivity.this, new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
            if(!documentSnapshots.isEmpty())
            {
                for(DocumentChange doc:documentSnapshots.getDocumentChanges())
                {
                    if(doc.getType()==DocumentChange.Type.ADDED)
                    {
                        chatModel obj = doc.getDocument().toObject(chatModel.class);
                        chatList.add(obj);
                        DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
                                .get(documentSnapshots.size() -1);
                        Query next = mFirestore.collection("Ideas").document(getTitle).collection("Discussions")
                                .orderBy("Time").startAfter(lastVisible);

                        adapter.notifyDataSetChanged();
                    }
                    if(doc.getType()==DocumentChange.Type.MODIFIED)
                    {
                        String docID = doc.getDocument().getId();
                        chatModel obj = doc.getDocument().toObject(chatModel.class);
                        if(doc.getOldIndex() == doc.getNewIndex())
                        {
                            chatList.set(doc.getOldIndex(),obj);
                        }
                        else
                        {
                            chatList.remove(doc.getOldIndex());
                            chatList.add(doc.getNewIndex(),obj);
                            adapter.notifyItemMoved(doc.getOldIndex(),doc.getNewIndex());
                        }
                        adapter.notifyDataSetChanged();
                    }
                }
            }
        }
    });

    LinearLayoutManager layoutManager = new LinearLayoutManager(DiscussionActivity.this);
    layoutManager.setReverseLayout(false);
    layoutManager.setStackFromEnd(false);

    mChatContainer.setHasFixedSize(false);
    mChatContainer.setLayoutManager(layoutManager);
    mChatContainer.setAdapter(adapter);
}

}

This is the activity_discussion.xml file :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DiscussionActivity"
android:background="#6D7993">

<android.support.v7.widget.RecyclerView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_above="@id/writingSection"
    android:id="@+id/chatContainer"
    android:layout_marginRight="5dp">
</android.support.v7.widget.RecyclerView>

<RelativeLayout
    android:id="@+id/writingSection"
    android:layout_width="379dp"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:background="@drawable/chat_background">

    <EditText
        android:id="@+id/textContent"
        android:layout_width="342dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="0dp"
        android:layout_toLeftOf="@id/include_documents"
        android:hint="Write here.." />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="28dp"
        android:src="@drawable/include_docs"
        android:id="@+id/include_documents"
        android:layout_toLeftOf="@id/sendMsg"
        android:layout_marginTop="9dp"
        android:layout_marginRight="3dp"/>

    <Button
        android:id="@+id/sendMsg"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="2dp"
        android:layout_marginTop="7dp"
        android:background="@drawable/send_message" />

</RelativeLayout>

This is the chatAdapter class :

public class chatAdapter extends 
RecyclerView.Adapter<chatAdapter.ViewHolder> {

private FirebaseAuth mAuth;
private FirebaseFirestore mFirestore;
private Context context;

private List<chatModel> chatMsgs;
private String title;

public chatAdapter(List<chatModel> chatMsgs,String title) {
    this.chatMsgs = chatMsgs;
    this.title = title;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int 
viewType) {

    mAuth = FirebaseAuth.getInstance();
    mFirestore = FirebaseFirestore.getInstance();
    context = parent.getContext();

    View view = 
LayoutInflater.from(context).inflate(R.layout.chat_box_layout,null);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final 
int position) {

    String getSenderId = chatMsgs.get(position).getSender();
    final String getSenderMessage = 
chatMsgs.get(position).getMessage();
    final String getID = chatMsgs.get(position).getId();
    final String theType = chatMsgs.get(position).getType();

    if(theType.equals("text"))
    {
        if(getSenderId.equals(mAuth.getCurrentUser().getUid()))
        {
            holder.aBox.setVisibility(View.GONE);
            holder.oIbox.setVisibility(View.GONE);
            holder.mIbox.setVisibility(View.GONE);
            //To get name...
            mFirestore.collection("Users").document(getSenderId).get()
                    .addOnCompleteListener((Activity) context, new 
OnCompleteListener<DocumentSnapshot>() {
                        @Override
                        public void onComplete(@NonNull 
Task<DocumentSnapshot> task) {
                            if(task.isSuccessful())
                            {
                                String getFirstName = 
task.getResult().getString("Firstname");
                                String getLastName = 
task.getResult().getString("Lastname");

                             holder.mName.setText(getFirstName.charAt(0)+getFirstName.substring(1).toLo .   werCase());
                            }
                        }
                    });

            holder.mContent.setText(getSenderMessage);

}
        if(!getSenderId.equals(mAuth.getCurrentUser().getUid())) {
            holder.mBox.setVisibility(View.GONE);
            holder.aEdit.setVisibility(View.GONE);
            holder.aDelete.setVisibility(View.GONE);

            holder.oIbox.setVisibility(View.GONE);
            holder.mIbox.setVisibility(View.GONE);

            //To get name...
            mFirestore.collection("Users").document(getSenderId).get()
                    .addOnCompleteListener((Activity) context, new OnCompleteListener<DocumentSnapshot>() {
                        @Override
                        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                            if (task.isSuccessful()) {
                                String getFirstName = task.getResult().getString("Firstname");
                                String getLastName = task.getResult().getString("Lastname");

                                holder.aName.setText(getFirstName.charAt(0) + getFirstName.substring(1).toLowerCase());
                            }
                        }
                    });
            holder.aContent.setText(getSenderMessage);
}
    }

}

@Override
public int getItemCount() {
    return chatMsgs.size();
}

public class ViewHolder extends RecyclerView.ViewHolder{


    //Variables for my chat lists...
    private TextView mName,mContent;
    private ImageView mDelete,mEdit;
    private RelativeLayout mBox;

    //Variable for other person's chat lists....
    private TextView aName,aContent;
    private ImageView aDelete,aEdit;
    private RelativeLayout aBox;

    //Variables for my images list..
    private RelativeLayout mIbox;
    private ImageView myImage,mIDelete;
    private TextView myNameInImage;

    //Variables for others image list..
    private RelativeLayout oIbox;
    private ImageView othersImage,oIDelete;
    private TextView othersNameInImage;

    public ViewHolder(View itemView) {
        super(itemView);

        //My variable initialization
        mName = (TextView)itemView.findViewById(R.id.name);
        mContent = (TextView)itemView.findViewById(R.id.chatContent);
        mDelete = (ImageView)itemView.findViewById(R.id.delete);
        mEdit = (ImageView)itemView.findViewById(R.id.editContent);
        mBox = (RelativeLayout)itemView.findViewById(R.id.userChatBox);

        //Other people's variables initialization..
        aName = (TextView)itemView.findViewById(R.id.othersName);
        aContent = (TextView)itemView.findViewById(R.id.othersChatContent);
        aDelete = (ImageView)itemView.findViewById(R.id.othersDelete);
        aEdit = (ImageView)itemView.findViewById(R.id.othersEditContent);
        aBox = (RelativeLayout)itemView.findViewById(R.id.othersChatBox);
}
}

Solution

  • Apparently i changed my single chat box item layout, like i tried to make the current user chatbox(My message) and the other user chatbox in the same layout and tried to hide it accordingly...As soon as I changed it that is i made two separate layouts : 1. my_chatbox - To show my messages 2. other_chatbox.xml - For others to send a message..

    and altered my adapter accordingly....

    And it works now, even for the images. :)

    here are codes : -

    my_chatbox.xml

        <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    
    
        <RelativeLayout
            android:id="@+id/userChatBox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:layout_alignParentTop="true">
    
            <RelativeLayout
                android:id="@+id/chatBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_marginLeft="5dp"
                android:background="@drawable/chat_background">
    
                <TextView
                    android:id="@+id/name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="20dp"
                    android:text="Name"
                    android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                    android:textColor="#000000"
                    android:textStyle="bold" />
    
                <TextView
                    android:id="@+id/chatContent"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/name"
                    android:layout_marginBottom="10dp"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="20dp"
                    android:text="Content"
                    android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                    android:textColor="#000000" />
    
            </RelativeLayout>
    
            <ImageView
                android:id="@+id/delete"
                android:layout_width="25dp"
                android:layout_height="15dp"
                android:layout_alignEnd="@+id/chatBox"
                android:layout_below="@+id/chatBox"
                android:layout_marginTop="-10dp"
                android:src="@drawable/delete" />
    
            <ImageView
                android:id="@+id/editContent"
                android:layout_width="25dp"
                android:layout_height="15dp"
                android:layout_below="@+id/chatBox"
                android:layout_marginTop="-10dp"
                android:layout_toStartOf="@+id/delete"
                android:src="@drawable/edit"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Small" 
        />
    
        </RelativeLayout>
    
        </RelativeLayout>
    

    the other_user_chatbox.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/userChatBox"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp">
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/chatBox"
            android:layout_marginLeft="5dp"
            android:layout_marginBottom="10dp"
            android:background="@drawable/chat_background"
            android:backgroundTint="#F4DDBB">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/name"
                android:text="Name"
                android:textColor="#000000"
    
    android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                android:textStyle="bold"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="20dp"/>
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/name"
    
    android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
                android:id="@+id/chatContent"
                android:text="Content"
                android:textColor="#000000"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="20dp"
                android:layout_marginBottom="10dp"/>
    
        </RelativeLayout>
    
        <ImageView
            android:id="@+id/othersDelete"
            android:layout_width="25dp"
            android:layout_height="15dp"
            android:layout_below="@id/chatBox"
            android:src="@drawable/delete" />
    
        <ImageView
            android:layout_width="25dp"
            android:layout_height="15dp"
            android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"
            android:layout_below="@id/chatBox"
            android:layout_toRightOf="@id/othersDelete"
            android:src="@drawable/edit"
            android:layout_marginRight="3dp"
            android:id="@+id/othersEditContent"/>
    
    </RelativeLayout>
    
    </RelativeLayout>
    

    Just try to keep the id's same in both the xml so as to make your viewHolder less complex.

    And this is my chatAdapter.class :

        public class chatAdapter extends RecyclerView.Adapter<chatAdapter.ViewHolder> {
    
        private FirebaseAuth mAuth;
        private FirebaseFirestore mFirestore;
        private Context context;
    
        private static final int SENT = 0;
        private static final int RECEIVED = 1;
        private String userID;
    
        private List<chatModel> chatMsgs;
        private String title;
    
        public chatAdapter(List<chatModel> chatMsgs,String title,String userID) {
            this.chatMsgs = chatMsgs;
            this.title = title;
            this.userID = userID;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            mAuth = FirebaseAuth.getInstance();
            mFirestore = FirebaseFirestore.getInstance();
            context = parent.getContext();
            View view = null;
            if(viewType == SENT)
            {
               view = 
        LayoutInflater.from(context).inflate(R.layout.chat_box_layout,parent,false);
            }
            if(viewType == RECEIVED)
            {
                view = 
     LayoutInflater.from(context).inflate(R.layout.other_user_chat_box,parent,false);
            }
    
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
    
            String getSenderId = chatMsgs.get(position).getSender();
            final String getSenderMessage = chatMsgs.get(position).getMessage();
            final String getID = chatMsgs.get(position).getId();
            final String theType = chatMsgs.get(position).getType();
    
            if(theType.equals("text"))
            {
                //To get name...
                mFirestore.collection("Users").document(getSenderId).get()
                        .addOnCompleteListener((Activity) context, new OnCompleteListener<DocumentSnapshot>() {
                            @Override
                            public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                if (task.isSuccessful()) {
                                    String getFirstName = task.getResult().getString("Firstname");
                                    String getLastName = task.getResult().getString("Lastname");
    
                                    holder.mName.setText(getFirstName.charAt(0) + getFirstName.substring(1).toLowerCase());
                                }
                            }
                        });
                holder.mContent.setText(getSenderMessage);
            }
    
        }
    
        @Override
        public int getItemCount() {
            return chatMsgs.size();
        }
    
        @Override
        public int getItemViewType(int position) {
            if (chatMsgs.get(position).getSender() . equals(userID))
                return SENT;
            else
                return RECEIVED;
            }
    
            public class ViewHolder extends RecyclerView.ViewHolder{
    
    
            //Variables for my chat lists...
            private TextView mName,mContent;
            private ImageView mDelete,mEdit;
            private RelativeLayout mBox;
    
            public ViewHolder(View itemView) {
                super(itemView);
    
                //variable initialization
                mName = (TextView)itemView.findViewById(R.id.name);
                mContent = (TextView)itemView.findViewById(R.id.chatContent);
                mDelete = (ImageView)itemView.findViewById(R.id.delete);
                mEdit = (ImageView)itemView.findViewById(R.id.editContent);
                mBox = (RelativeLayout)itemView.findViewById(R.id.userChatBox);
    
                }
            }
        }
    

    Hope it helps anyone else with the same problems and others too if they are interested.. :)