Wednesday, January 7, 2015

Android Client-Server Chat Application

This is a simple Android chat application which communicate with a Java server program. This tutorial will help you to understand socket programming in Android which sends information both ways.
To run this application, first execute the server program. You can run this application in your PC.

Then execute the client program. You can use your Android emulator or your Android device. If you are using Android emulator you can use IP address 10.0.2.2 to connect your sever which is running in the same computer. But if you are using an Android device you may have to change the IP address in the client app code according to your network configuration.
Once you execute the client app, the chat window will be opened in the server program. Type the message on the chat box and press "Send" button. The message will be appeared in the other end.

      
Android Chat App
 
Server Program





                                                         









                                                                                   
Following are the source codes of the main components of both programs.

Android Chat Application

<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/button1"
android:layout_alignLeft="@+id/editText1"
android:layout_alignParentTop="true"
android:layout_alignRight="@+id/button1"
android:layout_toLeftOf="@+id/button1" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Send" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button1"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/button1"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lakj.comspace.simpleclientserverchatapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.lakj.comspace.simpleclientserverchatapp.SimpleClientServerChatActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.lakj.comspace.simpleclientserverchatapp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/**
* This is the main activity class for Client-Server Chat App.
*
* @author Lak J Comspace (http://lakjeewa.blogspot.com)
*
*/
public class SimpleClientServerChatActivity extends Activity {
private EditText textField;
private Button button;
private TextView textView;
private Socket client;
private PrintWriter printwriter;
private BufferedReader bufferedReader;
//Following is the IP address of the chat server. You can change this IP address according to your configuration.
// I have localhost IP address for Android emulator.
private String CHAT_SERVER_IP = "10.0.2.2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textField = (EditText) findViewById(R.id.editText1);
button = (Button) findViewById(R.id.button1);
textView = (TextView) findViewById(R.id.textView1);
ChatOperator chatOperator = new ChatOperator();
chatOperator.execute();
}
/**
* This AsyncTask create the connection with the server and initialize the
* chat senders and receivers.
*/
private class ChatOperator extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... arg0) {
try {
client = new Socket(CHAT_SERVER_IP, 4444); // Creating the server socket.
if (client != null) {
printwriter = new PrintWriter(client.getOutputStream(), true);
InputStreamReader inputStreamReader = new InputStreamReader(client.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
} else {
System.out.println("Server has not bean started on port 4444.");
}
} catch (UnknownHostException e) {
System.out.println("Faild to connect server " + CHAT_SERVER_IP);
e.printStackTrace();
} catch (IOException e) {
System.out.println("Faild to connect server " + CHAT_SERVER_IP);
e.printStackTrace();
}
return null;
}
/**
* Following method is executed at the end of doInBackground method.
*/
@Override
protected void onPostExecute(Void result) {
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
final Sender messageSender = new Sender(); // Initialize chat sender AsyncTask.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
messageSender.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
messageSender.execute();
}
}
});
Receiver receiver = new Receiver(); // Initialize chat receiver AsyncTask.
receiver.execute();
}
}
/**
* This AsyncTask continuously reads the input buffer and show the chat
* message if a message is availble.
*/
private class Receiver extends AsyncTask<Void, Void, Void> {
private String message;
@Override
protected Void doInBackground(Void... params) {
while (true) {
try {
if (bufferedReader.ready()) {
message = bufferedReader.readLine();
publishProgress(null);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
@Override
protected void onProgressUpdate(Void... values) {
textView.append("Server: " + message + "\n");
}
}
/**
* This AsyncTask sends the chat message through the output stream.
*/
private class Sender extends AsyncTask<Void, Void, Void> {
private String message;
@Override
protected Void doInBackground(Void... params) {
message = textField.getText().toString();
printwriter.write(message + "\n");
printwriter.flush();
return null;
}
@Override
protected void onPostExecute(Void result) {
textField.setText(""); // Clear the chat box
textView.append("Client: " + message + "\n");
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

Server Program

package com.lakj.comspace.simplechatserver;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* This is the GUI component for chat window.
*
* @author Lak J Comspace (http://lakjeewa.blogspot.com)
*
*/
public class ChatWindow extends JFrame {
private JTextArea chatView;
private JButton sendButton;
private JTextArea chatBox;
/**
* This method open the chat window.
*
* @param clientSocket
* Socket which has been opened for chat
*/
public void open(final Socket clientSocket) {
initComponents();
setWinodwCloseListnerToCloseSocket(clientSocket);
initSenderAndReceiver(clientSocket);
}
/**
* This method initialize the components of the chat winodow.
*/
private void initComponents() {
chatView = new JTextArea(20, 46);
JScrollPane chatViewScrollPane = new JScrollPane(chatView);
chatBox = new JTextArea(5, 40);
JScrollPane chatBoxScrollPane = new JScrollPane(chatBox);
sendButton = new JButton("Send");
setResizable(false);
setTitle("Chat Server");
setSize(550, 450);
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(chatViewScrollPane);
contentPane.add(chatBoxScrollPane);
contentPane.add(sendButton);
chatView.setEditable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
/**
* This method initialize the chat sender and receiver for this chat window.
*
* @param clientSocket
* Socket which has been opened for chat
*/
private void initSenderAndReceiver(final Socket clientSocket) {
Receiver receiver = new Receiver(clientSocket, chatView);
final Sender sender = new Sender(clientSocket, chatView);
sendButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sender.sendMessage(chatBox.getText());
chatBox.setText(""); //Clear the chat box
}
});
Thread receiverThread = new Thread(receiver);
receiverThread.run();
}
/**
* This method register window closing listener to close the clientSocket
* when the chat window is closed.
*
* @param clientSocket
* Socket which has been opened for chat
*/
private void setWinodwCloseListnerToCloseSocket(final Socket clientSocket) {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
try {
clientSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
}
}
view raw ChatWindow.java hosted with ❤ by GitHub
package com.lakj.comspace.simplechatserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import javax.swing.JTextArea;
/**
* This is the chat receiver. This works as a thread and continuously check
* whether a message is available in the input buffer.
*
* @author Lak J Comspace (http://lakjeewa.blogspot.com)
*
*/
public class Receiver implements Runnable {
private BufferedReader bufferedReader;
private JTextArea chatView;
/**
* Public constructor.
*
* @param clientSocket
* Socket which has been opened for chat
* @param chatViewParam
* Chat history text area of chat window
*/
public Receiver(Socket clientSocket, JTextArea chatViewParam) {
chatView = chatViewParam;
try {
InputStreamReader inputStreamReader = new InputStreamReader(clientSocket.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
String message;
while (true) {
try {
if (bufferedReader.ready()) {
message = bufferedReader.readLine(); // Read the chat message.
chatView.append("Client: " + message + "\n"); // Print the chat message on chat window.
}
} catch (IOException ex) {
System.out.println("Problem in message reading");
ex.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
view raw Receiver.java hosted with ❤ by GitHub
package com.lakj.comspace.simplechatserver;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JTextArea;
/**
* This is the chat sender.
*
* @author Lak J Comspace (http://lakjeewa.blogspot.com)
*
*/
public class Sender {
private PrintWriter out;
private JTextArea chatView;
/**
* Public constructor.
*
* @param clientSocket
* Socket which has been opened for chat
* @param chatViewParam
* Chat history text area of chat window
*/
public Sender(Socket clientSocket, JTextArea chatViewParam) {
chatView = chatViewParam;
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
out.println(message); // Print the message on output stream.
chatView.append("Server: " + message + "\n"); // Print the message on chat window.
}
}
view raw Sender.java hosted with ❤ by GitHub
package com.lakj.comspace.simplechatserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* This is the main class for chat server.
*
* @author Lak J Comspace (http://lakjeewa.blogspot.com)
*
*/
public class SimpleChatServer {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(4444);
System.out.println("Server started. Listening to the port 4444. Waitng for the client.");
clientSocket = serverSocket.accept();
System.out.println("Client connected on port 4444.");
} catch (IOException e) {
System.out.println("Could not listen on port: 4444");
e.printStackTrace();
return;
}
ChatWindow chatWindow = new ChatWindow();
chatWindow.open(clientSocket);
}
}

Following are the both Android client and Java server complete projects. You can clone or download them as zips from Git-Hub.

Git-Hub HTTPS clone URL: https://github.com/lakjcomspace/AndroidChatClientServer.git
Git-Hub Repository URL: https://github.com/lakjcomspace/AndroidChatClientServer
Download as a Zip: https://github.com/lakjcomspace/AndroidChatClientServer/archive/master.zip

You can run the projects by importing them to the IDE. Or just create you own project and copy and paste above source files.

41 comments:

  1. I executed the application but i wanted to know if i received a string from the client and i assigned it to a variable and wanted to apply a function on that variable and then send it back. Is it gonna be easy to do that. I already asigned the string received to a variable in the "simplechatserver.Receiver" class but i don't know how to use that variable in the Sender class.

    ReplyDelete
    Replies
    1. Yes its easy, you can do that.
      You should do this in the sever program. Both "Receiver" and "Seder" are initialized in the "ChatWindow" class. Therefore the common place for both "Receiver" and "Seder" is "ChatWindow" class. Keep global references (variables) to both "Receiver" and "Seder". Create method inside "ChatWindow" which does your particular string operation and call receiver to send the message. Pass a reference to ChatWindow class when you create the Receiver class. You should change the Receiver class constructor to do that. From that you may be able to call your particular method when the Receiver receives a message. You should call that method after line number 50 of Receiver.java class.
      Hope you can understand my guideline. :)

      Delete
    2. and actually what i want to do is per example : i send a number ( ex : 17 ) to the server and the server sum this number with another number and return the result to the android client.
      I kinda don't fully understand what you wrote.

      Delete
    3. String string = message;
      String[] parts = string.split("-");
      String part1 = parts[0];
      String part2 = parts[1];
      i added these lines after "message = bufferedReader.readLine(); // Read the chat message. "
      so that i split the string that i am receiving.
      than i want to apply a method to these strings example func ( part1,part2,number1,number2)
      and then send the result back to the client.

      Delete
    4. I can present whole answer from a comment, but i will brief and highlight the most important places you should change. Following are the ChatWindow and Receiver classes. This will help you to understand the above comment.

      -----------------------------------------------------------------------------------------------------------------------------
      public class ChatWindow{

      private void initSenderAndReceiver(final Socket clientSocket) {
      // Using this key word you can pass the reference to ChatWindow to the Receiver.
      Receiver receiver = new Receiver(clientSocket, chatView, this);

      }

      public void yourMethod(String message){
      // do here whatever you want.
      }

      ------------------------------------------------------------------------------------------------------------------------------------
      public class Receiver{

      private ChatWindow chatWindow;

      public Receiver(Socket clientSocket, JTextArea chatViewParam,ChatWindow chatWindowParam) {
      chatWindow = chatWindowParam;
      }

      @Override
      public void run() {
      // Here inside the while loop you can do the following.
      chatWindow.yourMethod(message);
      }
      }

      Delete
    5. I understood this part, but you didn't mention how to send the result of the method back to the android client.
      I am sorry for asking these much of questions, but i want to understand.

      Delete
    6. In my first comment i told you to keep global variables for "Sender" and "Receiver" in the ChatWindow class. Let's say Sender's global variable is "sender" (private Sender sender;). You are calling yourMethod(String message) which is in the ChatWindow class. So you can simply call the sender.sendMessage(String message) method inside youMethod.
      Your method will look like:

      public void yourMethod(String message){

      // Do whatever you want here. Lets say you are producing
      // a string called "yourString" after all your manipulations on "message".
      // Then add the following line to this method.
      sender.sendMessage(yourString);

      }

      Delete
    7. Ok, Thanks a lot, now i understood.

      Delete
  2. Hi,
    i got output from android emulator with PC.
    but How can i Communicate with android device with PC through wifi.
    can you give your Reply?

    ReplyDelete
  3. Hi,
    Is it possible the client connect to the server through internet instead of local network?

    ReplyDelete
    Replies
    1. Yes, but your server should be publicly accessible. That means, you should host your server program in a real web server.

      Delete
  4. Hi Madhu,
    The client will lost connection with the server if stop chatting for few minutes, any idea on this or preventive can be done?

    ReplyDelete
  5. This website was... how do I say it? Relevant!
    ! Finally I have found something that helped me. Appreciate
    it!

    Feel free to visit my weblog www.freshappz.com

    ReplyDelete
  6. I need your help to break out some functionality in the client side.
    Right now when the app is started, the socket is created and listens for incoming server messages.
    I would like to connect creation of the socket to a button so when I click on the connectButton then socket is being created in the background

    Cheers
    Masoud

    ReplyDelete
    Replies
    1. Hi Masoud,
      Sorry for the delay. It is possible, you can simply do it. I will explain.
      You know that, now the socket is created when the app is started. That is true. Actually the onCreate() method (line 40) is called when the application is started. There a ChatOperator object is created and chatOperator.execute() method create the socket.

      Create a new button (like in line 44) for your "Connect" button. Then add the following lines of code instead of lines 47 and 48.

      boolean isConnectButtonClicked = false;
      connectButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
      if(! isConnectButtonClicked ){
      isConnectButtonClicked = true;
      ChatOperator chatOperator = new ChatOperator();
      chatOperator.execute();
      }
      });

      What the above few lines does is, a click action listener is bound so that the socket creation happens when the button is clicked. isConnectButtonClicked boolean variable will keep the status of connect button clicked status. The user should only be able to connect once, otherwise the the socket will create again and again at the each time the user click the button.

      Hope you understand my explanation. If not, don't hesitate to keep asking the questions. :)

      Delete
    2. Thanks, it worked like a charm.
      However I have a disconnect button as well. Once I click on that, it releases the socket and enable the connect button. As the connect button now is inside the Oncreate procedure, it will never be called for a second time when I click on it. You can find the code here:
      http://www.testlead.se/android/MainActivity.java

      Delete
  7. This tutorial will help you to understand socket programming in Android which sends information both ways. Cell Phone Tracker Online For Free

    ReplyDelete
  8. my client app is saying "unfortunately app has stoped working" when i installed on my phone.. could u help me plz?
    thank u!

    ReplyDelete
    Replies
    1. The error message you have mentioned is so general. That is not enough to understand the issue. Can you find the server responses or error log entries?

      Delete
  9. This post is likeable, and your blog is very interesting, congratulations :-)

    ReplyDelete
  10. Hi Madhu
    I want to have server on another android device not on the PC. What should I change in server code?
    Thanks

    ReplyDelete
    Replies
    1. You can do it. You just want to create an android app which does the server functionality. You can use the same code handle server side functionality. But creating the network between the android devices is the trickiest part. :)

      Delete
    2. Hi Madhu
      I have tried a lot trying to put server on android device but it was difficult.Can you plz help me

      Delete
  11. I am new in android and java Would you please change code to android?

    ReplyDelete
  12. It makes so many errors on changing code to android

    ReplyDelete
  13. Can we save the chat? If so please let me know

    ReplyDelete
    Replies
    1. Yes, you can be done. But in the tutorial i haven't implement it. If you close the app, every chat messages will be lost.

      Delete
  14. can we put the server program in android

    ReplyDelete
  15. Hi, Can we make one to one chatting through this code?. If yes can you please suggest how we can achieve this.

    ReplyDelete
    Replies
    1. Yes,This is already an one to one chat since the server is accepting only one chat client. But if you want advance options like authentication, you need to implement it. :)

      Delete
  16. Hi Lakjeewa,

    Using above code how we can do one(server) to many(client) communication.

    Generally we aware of that Chat concept. how to achieve using code.

    Ex. Sanjay(client) send request and Shyam(client) send a request
    Now Server accept both request then Server how to identify which client have requested. so response only them.

    ReplyDelete
    Replies
    1. Your requirement is bit of advance than the tutorial.
      If you go through the server program you will see that i am creating only one thread for receiver(Client). Just look at line #87 in ChatWindow class. If you are going to have more client you may have to create threads for each.

      Delete
    2. Thanks for you suggestion but just i want to know a little bit idea/example.

      If i will be implement by using multi thread it will be possible to multiple client communicate with the Server at time simultaneously. Could you please guide me or suggest/idea/ or provide me the code how to implement it.

      Thanks

      Delete
  17. Hi ,

    Can we write and read cookies in Android WebView. Example :

    1. Any webpage open in WebView Intent in application.and set cookies in device. now that stored cookies. can we read from another android application which is another application.(Cookies communicate within two application one application is doing write cookies and second application read that stored cookies.)

    is it possible to achieve it. if yes pls help..

    ReplyDelete
  18. Hello,
    I am getting NullPointerException at Client side. Here is my logcat view that shows exception in detail. Please Help me out for this.


    E/AndroidRuntime(12635): java.lang.RuntimeException: An error occured while executing doInBackground()
    E/AndroidRuntime(12635): at android.os.AsyncTask$3.done(AsyncTask.java:304)
    E/AndroidRuntime(12635): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    E/AndroidRuntime(12635): at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    E/AndroidRuntime(12635): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    E/AndroidRuntime(12635): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    E/AndroidRuntime(12635): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    E/AndroidRuntime(12635): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    E/AndroidRuntime(12635): at java.lang.Thread.run(Thread.java:818)
    E/AndroidRuntime(12635): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.io.BufferedReader.ready()' on a null object reference
    E/AndroidRuntime(12635): at com.example.demochatappclient.MainActivity$Receiver.doInBackground(MainActivity.java:110)
    E/AndroidRuntime(12635): at com.example.demochatappclient.MainActivity$Receiver.doInBackground(MainActivity.java:1)
    E/AndroidRuntime(12635): at android.os.AsyncTask$2.call(AsyncTask.java:292)
    E/AndroidRuntime(12635): at java.util.concurrent.FutureTask.run(FutureTask.java:237)

    ReplyDelete
  19. how to run this project on android studio please help me

    ReplyDelete
  20. How many threads are running on server? Could you please explain them.

    ReplyDelete
  21. is it possible to communicate between pc to pc,mobile to pc,pc to mobile and mobile to mobile through this app?

    ReplyDelete
    Replies
    1. This particular scenario has been implemented to communicate between mobile and pc. But you can change this program to cater all scenarios you have mentioned.

      Delete
  22. Thank you.

    It's been a lot of help in solving this problem.

    ReplyDelete