How to Implement Chat Functionality in Social Media Android App?
This is the Part 14 of “Build a Social Media App on Android Studio” tutorial, and we are going to cover the following functionalities in this article:
- We are going to Create a Layout for chat & Send Messages in Chat.
- A user can send either a Message or an Image.
- A user can send an image either using a camera or gallery.
- Firstly a request for permission will be asked to send an image using a gallery or after clicking the image using the camera.
- If permission is given then the user can send the image, or it will again request for asking permission.
Step By Step Implementation
Step 1: Create two new layout resource files and name them row_chat_left and row_chat_right
Working with the row_chat_left.xml file. The received message will be on the left side. Similarly, Working with the row_chat_right.xml file. The message sends to the user will be on the right side. Below is the code for the row_chat_left.xml file and row_chat_right.xml file.
XML
< LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id = "@+id/msglayout"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "vertical"
android:padding = "10dp" >
< LinearLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "horizontal" >
< de.hdodenhof.circleimageview.CircleImageView
android:id = "@+id/profilec"
android:layout_width = "50dp"
android:layout_height = "50dp"
android:src = "@drawable/profile_image"
app:civ_border_color = "@null" />
android:id = "@+id/msgc"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:background = "@drawable/bg_receiver"
android:padding = "15dp"
android:text = "His Message"
android:textColor = "@color/colorBlack"
android:textSize = "16sp"
android:visibility = "gone" />
android:id = "@+id/images"
android:layout_width = "200dp"
android:layout_height = "200dp"
android:adjustViewBounds = "true"
android:background = "@drawable/bg_receiver"
android:padding = "15dp"
android:scaleType = "fitCenter"
android:src = "@drawable/ic_images" />
android:id = "@+id/timetv"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "02/01/1990 06:19PM"
android:textColor = "@color/colorBlack"
android:textSize = "12sp" />
android:id = "@+id/isSeen"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "end"
android:text = "Delivered"
android:textAlignment = "textEnd"
android:visibility = "gone" />
XML
< LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id = "@+id/msglayout"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "vertical"
android:padding = "10dp" >
< RelativeLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "horizontal" >
< de.hdodenhof.circleimageview.CircleImageView
android:id = "@+id/profilec"
android:layout_width = "50dp"
android:layout_height = "50dp"
android:src = "@drawable/profile_image"
android:visibility = "gone"
app:civ_border_color = "@null" />
android:id = "@+id/timetv"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "02/01/1990 06:19PM"
android:textColor = "@color/colorBlack"
android:textSize = "12sp" />
android:id = "@+id/msgc"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_alignParentEnd = "true"
android:layout_toEndOf = "@id/timetv"
android:background = "@drawable/bg_sender"
android:padding = "15dp"
android:text = "His Message"
android:textColor = "@color/colorBlack"
android:textSize = "16sp" />
android:id = "@+id/images"
android:layout_width = "200dp"
android:layout_height = "200dp"
android:layout_alignParentEnd = "true"
android:adjustViewBounds = "true"
android:background = "@drawable/bg_sender"
android:padding = "15dp"
android:scaleType = "fitCenter"
android:src = "@drawable/ic_images" />
android:id = "@+id/isSeen"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:gravity = "end"
android:text = "Delivered"
android:textAlignment = "textEnd" />
Step 2: Working with the activity_chat.xml file
Here In the RecyclerView, we will be showing all the messages. In the TextView user will type the message and using the send button user will send the message. Below is the code for the activity_chat.xml file.
XML
< RelativeLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:tools = "http://schemas.android.com/tools"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".ChatActivity" >
< androidx.appcompat.widget.Toolbar
android:id = "@+id/toolbar"
android:layout_width = "match_parent"
android:layout_height = "?android:attr/actionBarSize"
android:background = "@color/colorPrimaryDark"
android:theme = "@style/ThemeOverlay.AppCompat.Dark.ActionBar" >
< LinearLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "horizontal" >
< de.hdodenhof.circleimageview.CircleImageView
android:id = "@+id/profiletv"
android:layout_width = "35dp"
android:layout_height = "35dp"
android:scaleType = "centerCrop"
android:src = "@drawable/profile_image"
app:civ_circle_background_color = "@color/colorPrimaryDark" />
< LinearLayout
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginStart = "20dp"
android:layout_marginLeft = "20dp"
android:layout_weight = "1"
android:gravity = "center"
android:orientation = "vertical" >
android:id = "@+id/nameptv"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:text = "HisName"
android:textColor = "@color/colorWhite"
android:textSize = "18sp"
android:textStyle = "bold" />
android:id = "@+id/onlinetv"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:text = "Online"
android:textColor = "@color/colorWhite"
android:textStyle = "bold" />
android:id = "@+id/block"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_gravity = "center_vertical"
android:layout_marginEnd = "5dp"
android:src = "@drawable/ic_unblock" />
< androidx.recyclerview.widget.RecyclerView
android:id = "@+id/chatrecycle"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_above = "@id/chatlayout"
android:layout_below = "@id/toolbar" />
< LinearLayout
android:id = "@+id/chatlayout"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_alignParentBottom = "true"
android:background = "@color/colorWhite"
android:gravity = "center"
android:orientation = "horizontal" >
< ImageButton
android:id = "@+id/attachbtn"
android:layout_width = "50dp"
android:layout_height = "50dp"
android:background = "@null"
android:src = "@drawable/ic_iattach" />
android:id = "@+id/messaget"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_weight = "1"
android:background = "@null"
android:hint = "Start Typing"
android:inputType = "textCapSentences|textMultiLine"
android:padding = "15dp" />
< ImageButton
android:id = "@+id/sendmsg"
android:layout_width = "40dp"
android:layout_height = "40dp"
android:background = "@null"
android:src = "@drawable/send_message" />
Step 3: Working with the row_chatlist.xml file
Create another layout resource file and name the file as row_chatlist. Below is the code for the row_chatlist.xml file.
XML
< androidx.cardview.widget.CardView
xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:orientation = "vertical"
app:contentPadding = "3dp" >
< RelativeLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content" >
< de.hdodenhof.circleimageview.CircleImageView
android:id = "@+id/profileimage"
android:layout_width = "70dp"
android:layout_height = "70dp"
android:src = "@drawable/profile_image" />
< de.hdodenhof.circleimageview.CircleImageView
android:id = "@+id/onlinestatus"
android:layout_width = "25dp"
android:layout_height = "25dp" />
android:id = "@+id/nameonline"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginStart = "4dp"
android:layout_toEndOf = "@id/profileimage"
android:layout_toRightOf = "@id/profileimage"
android:text = "His Name"
android:textColor = "@color/colorBlack"
android:textSize = "18sp" />
android:id = "@+id/lastmessge"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_below = "@id/nameonline"
android:layout_marginStart = "4dp"
android:layout_toEndOf = "@id/profileimage"
android:layout_toRightOf = "@id/profileimage"
android:maxLines = "2"
android:text = "Last Message"
android:textColor = "@color/colorBlack" />
android:id = "@+id/blocking"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_alignParentEnd = "true"
android:layout_gravity = "center_vertical"
android:src = "@drawable/ic_unblock" />
android:id = "@+id/seen"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_below = "@id/blocking"
android:layout_alignParentEnd = "true"
android:layout_gravity = "center_vertical"
android:src = "@drawable/ic_unblock" />
Step 4: Working with the ModelChat.java file
Created this class to initialize the key so that we can retrieve the value of the key later.
Java
package com.example.socialmediaapp;
public class ModelChat <
String message;
public String getMessage() <
return message;
public void setMessage(String message) <
this .message = message;
public String getReceiver() <
return receiver;
public void setReceiver(String receiver) <
this .receiver = receiver;
public String getSender() <
return sender;
public void setSender(String sender) <
this .sender = sender;
public String getTimestamp() <
return timestamp;
public void setTimestamp(String timestamp) <
this .timestamp = timestamp;
public boolean isDilihat() <
return dilihat;
public void setDilihat( boolean dilihat) <
this .dilihat = dilihat;
String receiver;
public ModelChat() <
String sender;
public String getType() <
return type;
public void setType(String type) <
this .type = type;
public ModelChat(String message, String receiver, String sender, String type, String timestamp, boolean dilihat)
this .message = message;
this .receiver = receiver;
this .sender = sender;
this .type = type;
this .timestamp = timestamp;
this .dilihat = dilihat;
String type;
String timestamp;
boolean dilihat;
Step 5: Working with the AdpaterChat.java file
Create a new java class and name the class as AdpaterChat. Below is the code for the AdpaterChat.java file.
Java
package com.example.socialmediaapp;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import de.hdodenhof.circleimageview.CircleImageView;
public class AdapterChat extends RecyclerView.Adapter
private static final int MSG_TYPE_LEFT = 0 ;
private static final int MSG_TYPR_RIGHT = 1 ;
Context context;
String imageurl;
FirebaseUser firebaseUser;
public AdapterChat(Context context, List list, String imageurl)
this .context = context;
this .list = list;
this .imageurl = imageurl;
public Myholder onCreateViewHolder( @NonNull ViewGroup parent, int viewType) <
if (viewType == MSG_TYPE_LEFT) <
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_left, parent, false );
return new Myholder(view);
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_right, parent, false );
return new Myholder(view);
public void onBindViewHolder( @NonNull Myholder holder, final int position) <
String message = list.get(position).getMessage();
String timeStamp = list.get(position).getTimestamp();
String type = list.get(position).getType();
Calendar calendar = Calendar.getInstance(Locale.ENGLISH);
calendar.setTimeInMillis(Long.parseLong(timeStamp));
String timedate = DateFormat.format( "dd/MM/yyyy hh:mm aa" , calendar).toString();
holder.message.setText(message);
holder.time.setText(timedate);
Glide.with(context).load(imageurl).into(holder.image);
> catch (Exception e) <
if (type.equals( "text" )) <
holder.message.setVisibility(View.VISIBLE);
holder.mimage.setVisibility(View.GONE);
holder.message.setText(message);
holder.message.setVisibility(View.GONE);
holder.mimage.setVisibility(View.VISIBLE);
Glide.with(context).load(message).into(holder.mimage);
holder.msglayput.setOnClickListener( new View.OnClickListener() <
public void onClick(View v) <
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle( "Delete Message" );
builder.setMessage( "Are You Sure To Delete This Message" );
builder.setPositiveButton( "Delete" , new DialogInterface.OnClickListener() <
public void onClick(DialogInterface dialog, int which) <
deleteMsg(position);
builder.setNegativeButton( "Cancel" , new DialogInterface.OnClickListener() <
public void onClick(DialogInterface dialog, int which) <
dialog.dismiss();
builder.create().show();
private void deleteMsg( int position) <
final String myuid = FirebaseAuth.getInstance().getCurrentUser().getUid();
String msgtimestmp = list.get(position).getTimestamp();
DatabaseReference dbref = FirebaseDatabase.getInstance().getReference().child( "Chats" );
Query query = dbref.orderByChild( "timestamp" ).equalTo(msgtimestmp);
query.addListenerForSingleValueEvent( new ValueEventListener() <
public void onDataChange( @NonNull DataSnapshot dataSnapshot) <
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) <
if (dataSnapshot1.child( "sender" ).getValue().equals(myuid)) <
// any two of below can be used
dataSnapshot1.getRef().removeValue();
/* HashMap hashMap = new HashMap<>();
hashMap.put("message", "This Message Was Deleted");
dataSnapshot1.getRef().updateChildren(hashMap);
Toast.makeText(context,"Message Deleted. ",Toast.LENGTH_LONG).show();
Toast.makeText(context, "you can delete only your msg. " , Toast.LENGTH_LONG).show();
public void onCancelled( @NonNull DatabaseError databaseError) <
public int getItemCount() <
return list.size();
public int getItemViewType( int position) <
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (list.get(position).getSender().equals(firebaseUser.getUid())) <
return MSG_TYPR_RIGHT;
return MSG_TYPE_LEFT;
class Myholder extends RecyclerView.ViewHolder <
CircleImageView image;
ImageView mimage;
TextView message, time, isSee;
LinearLayout msglayput;
public Myholder( @NonNull View itemView) <
super (itemView);
image = itemView.findViewById(R.id.profilec);
message = itemView.findViewById(R.id.msgc);
time = itemView.findViewById(R.id.timetv);
isSee = itemView.findViewById(R.id.isSeen);
msglayput = itemView.findViewById(R.id.msglayout);
mimage = itemView.findViewById(R.id.images);
Step 6: Working with the ChatActivity.java file
We are Reading the user message from “Chats” Node in Firebase. Every time data changes this data will change accordingly
chatList=new ArrayList<>(); DatabaseReference dbref= FirebaseDatabase.getInstance().getReference().child("Chats");
Loading the Data setting data value using adapter chat
ModelChat modelChat=dataSnapshot1.getValue(ModelChat.class); if(modelChat.getSender().equals(myuid)&& modelChat.getReceiver().equals(uid)|| modelChat.getReceiver().equals(myuid) && modelChat.getSender().equals(uid)) < chatList.add(modelChat);//add the chat in chatlist >adapterChat=new AdapterChat(ChatActivity.this,chatList,image); adapterChat.notifyDataSetChanged(); recyclerView.setAdapter(adapterChat);
Sending Messages in Chat Reference node value. Here is how we are saving data in the Firebase Realtime database
DatabaseReference databaseReference= FirebaseDatabase.getInstance().getReference(); String timestamp=String.valueOf(System.currentTimeMillis()); HashMap hashMap=new HashMap<>(); hashMap.put("sender",myuid); hashMap.put("receiver",uid); hashMap.put("message",message); hashMap.put("timestamp",timestamp); hashMap.put("dilihat",false); hashMap.put("type","text"); databaseReference.child("Chats").push().setValue(hashMap);
Below is the code for the ChatActivity.java file.