Monday, August 18, 2014

Simple Android Chat Application, client side.

It's client side of Simple Android Chat Application, for the server side, refer last post "Implement simple Android Chat Application, server side".


MainActivity.java
package com.example.androidchatclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
 
 static final int SocketServerPORT = 8080;
 
 LinearLayout loginPanel, chatPanel;

 EditText editTextUserName, editTextAddress;
 Button buttonConnect;
 TextView chatMsg, textPort;
 
 EditText editTextSay;
 Button buttonSend;
 Button buttonDisconnect;

 String msgLog = "";
 
 ChatClientThread chatClientThread = null;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  loginPanel = (LinearLayout)findViewById(R.id.loginpanel);
  chatPanel = (LinearLayout)findViewById(R.id.chatpanel);

  editTextUserName = (EditText) findViewById(R.id.username);
  editTextAddress = (EditText) findViewById(R.id.address);
  textPort = (TextView) findViewById(R.id.port);
  textPort.setText("port: " + SocketServerPORT);
  buttonConnect = (Button) findViewById(R.id.connect);
  buttonDisconnect = (Button) findViewById(R.id.disconnect);
  chatMsg = (TextView) findViewById(R.id.chatmsg);

  buttonConnect.setOnClickListener(buttonConnectOnClickListener);
  buttonDisconnect.setOnClickListener(buttonDisconnectOnClickListener);
  
  editTextSay = (EditText)findViewById(R.id.say);
  buttonSend = (Button)findViewById(R.id.send);
  
  buttonSend.setOnClickListener(buttonSendOnClickListener);
 }
 
 OnClickListener buttonDisconnectOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   if(chatClientThread==null){
    return;
   }
   chatClientThread.disconnect();
  }
  
 };
 
 OnClickListener buttonSendOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   if (editTextSay.getText().toString().equals("")) {
    return;
   }
   
   if(chatClientThread==null){
    return;
   }
   
   chatClientThread.sendMsg(editTextSay.getText().toString() + "\n");
  }
  
 };

 OnClickListener buttonConnectOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   String textUserName = editTextUserName.getText().toString();
   if (textUserName.equals("")) {
    Toast.makeText(MainActivity.this, "Enter User Name",
      Toast.LENGTH_LONG).show();
    return;
   }

   String textAddress = editTextAddress.getText().toString();
   if (textAddress.equals("")) {
    Toast.makeText(MainActivity.this, "Enter Addresse",
      Toast.LENGTH_LONG).show();
    return;
   }
   
   msgLog = "";
   chatMsg.setText(msgLog);
   loginPanel.setVisibility(View.GONE);
   chatPanel.setVisibility(View.VISIBLE);

   chatClientThread = new ChatClientThread(
     textUserName, textAddress, SocketServerPORT);
   chatClientThread.start();
  }

 };

 private class ChatClientThread extends Thread {

  String name;
  String dstAddress;
  int dstPort;
  
  String msgToSend = "";
  boolean goOut = false;

  ChatClientThread(String name, String address, int port) {
   this.name = name;
   dstAddress = address;
   dstPort = port;
  }

  @Override
  public void run() {
   Socket socket = null;
   DataOutputStream dataOutputStream = null;
   DataInputStream dataInputStream = null;

   try {
    socket = new Socket(dstAddress, dstPort);
    dataOutputStream = new DataOutputStream(
      socket.getOutputStream());
    dataInputStream = new DataInputStream(socket.getInputStream());
    dataOutputStream.writeUTF(name);
    dataOutputStream.flush();

    while (!goOut) {
     if (dataInputStream.available() > 0) {
      msgLog += dataInputStream.readUTF();

      MainActivity.this.runOnUiThread(new Runnable() {

       @Override
       public void run() {
        chatMsg.setText(msgLog);
       }
      });
     }
     
     if(!msgToSend.equals("")){
      dataOutputStream.writeUTF(msgToSend);
      dataOutputStream.flush();
      msgToSend = "";
     }
    }

   } catch (UnknownHostException e) {
    e.printStackTrace();
    final String eString = e.toString();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
     }
     
    });
   } catch (IOException e) {
    e.printStackTrace();
    final String eString = e.toString();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
     }
     
    });
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataOutputStream != null) {
     try {
      dataOutputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataInputStream != null) {
     try {
      dataInputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      loginPanel.setVisibility(View.VISIBLE);
      chatPanel.setVisibility(View.GONE);
     }
     
    });
   }

  }
  
  private void sendMsg(String msg){
   msgToSend = msg;
  }
  
  private void disconnect(){
   goOut = true;
  }
 }

}

/res/layout/activity_main.xml
<LinearLayout 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:orientation="vertical"
    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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Char Client"
        android:textStyle="bold" />

    <LinearLayout
        android:id="@+id/loginpanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="visible" >

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="User name" />

        <EditText
            android:id="@+id/address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="dstAddress" />

        <TextView
            android:id="@+id/port"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/connect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Connect..." />
    </LinearLayout>

 <LinearLayout
        android:id="@+id/chatpanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="gone" >
        
        <EditText
            android:id="@+id/say"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Say something" />
     
        <Button
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Send" />
        
        <Button
            android:id="@+id/disconnect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Disconnect" />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <TextView
                android:id="@+id/chatmsg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </ScrollView>
    </LinearLayout>

</LinearLayout>

Permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

17 comments:

Assanee Suksiritantawan said...

So good

shubham said...

sir i am new to to wifi api ..i could not download the files attached .so i copy pasted the code and edited the manifest file .and copied the appcompat file to the project .but it is stopping on startup saying in logcat NoClassDefFound..Please guide me

Raju Dutta said...

Can't connect to server from another device, am i need to port forward or something else?

Oğuz Artiran said...

I am not sure but I think when client disconnect from the application, Toast that writes "removed" does not seem immediately.It is seen after a new client connects and sends a message.How can i handle this? Thanks for the answers.

Anonymous said...

Hi good sir, how come you don't get a "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views" error?
It seems that you are calling chatMsg.setText from within the clientChatThread, but chatMsg was made in the MainActivity thread. Intuitively I would do this as well but I've been getting this error, do you have any work-arounds to this error? Thanks1

Andr.oid Eric said...

hello Anonymous,

To prevent "CalledFromWrongThreadException...":

MainActivity.this.runOnUiThread(new Runnable() {

@Override
public void run() {
chatMsg.setText(msgLog);
}
});

This will create a Runnable to run in ui thread.

Resilience soft said...

Sir how we can chat with individual in different Router

Iam Ests said...

thank for this application ,but i want know if i can create other ChatRoom or GroupChat in this app

Andr.oid Eric said...

I think it is depends on you.

raju mahato said...

sir
what is the username and destAddress to connect

Andr.oid Eric said...

hello raju mahato,
username is any name you choice.
destAddress is the IP address of the server, it will be shown in Server side app.

calangoFOZ said...

tks tks tks

kartzy said...

Firstly, Thats a very nice code :)
Can you plz guide me as to also implement small files transfer in this application?? I tried going through a lot of stuff like xmpp etc but is there something more simpler?

Ahsan Khan said...

Dear I need such type of communication as between client and server as in
http://android-er.blogspot.com/2014/08/implement-simple-android-chat.html
presented but using 3G/4G services.

What you want to suggest me, type of hint/method to do to achieve this.

Unknown said...

Is it Tcp application?

luobna saleh said...

how to prevent java.net.socketException

pratik pachpor said...

awesome & loved it, tutorial is working finely