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.

26 comments:

  1. 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

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

    ReplyDelete
  3. 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.

    ReplyDelete
  4. 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

    ReplyDelete
  5. 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.

    ReplyDelete
  6. Sir how we can chat with individual in different Router

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

    ReplyDelete
  8. sir
    what is the username and destAddress to connect

    ReplyDelete
  9. 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.

    ReplyDelete
  10. 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?

    ReplyDelete
  11. 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.

    ReplyDelete
  12. how to prevent java.net.socketException

    ReplyDelete
  13. awesome & loved it, tutorial is working finely

    ReplyDelete
  14. Hi, this is great, but may i ask how to make the text to not repeat if i send, i mean i want to replace the current text with the new one sent from server or also client,

    i believe we need to change something here;

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

    MainActivity.this.runOnUiThread(new Runnable() {

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

    }

    ReplyDelete
  15. Hello Ezra Alvaro Manuel,

    It's a old exercise, i also forgot the details.

    The point is what's new or old. For human understanding, client enter text "abc" then send, then enter "cde" then send. "abc" is old, "cde" is new.

    What the machine view (in my understanding), it's "a", "b", "c", "d", "e", "f". It don't know when you click the send button. And the code if(dataInputStream.available() > 0){} will not handle it. May be it will receive "a", "bcd", "ef", or "abcd", "e", "f", no guarantee.

    So I will suggest to insert some signature (such as "NL"(new line), "CR"(carriage return)) in the end of the text in client side. Such that the service side can check the signature to clear msgLog.

    hope can help.

    ReplyDelete
  16. HY WHERE CAN I RECEIVE THE MESSAGES LIKE SHOWN ATT THE TABLETTE

    ReplyDelete
  17. hello Anonymous,

    Refer "Implement simple Android Chat Application, server side (http://android-er.blogspot.com/2014/08/implement-simple-android-chat.html)"

    ReplyDelete
  18. I need permission to download the files. Can I please get dot compliance permission?

    ReplyDelete
  19. Hello Isha Sinha,

    ??? Already set public, no permission needed.

    Or you try to download here (https://sites.google.com/site/androidexercise2/download/AndroidChatClient_20140818a.zip) to by-pass the adv. page.

    ReplyDelete
  20. Hello,

    I can't receive data from server? I am using an another server, python server.

    Can you give any clue? Thanks

    ReplyDelete
  21. awesome.. so useful. helped it alot. thank u

    ReplyDelete
  22. awesome work.will u please help me I want to send messages from the server also.is it possible???

    ReplyDelete