Mainactivity.java
package com.example.mtk28093.chatclient;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
private String TAG = "zijian_chatClient";
private enum ConStatus{
DISCONNECTED,CONNECTING,CONNECTED
}
private InetAddress serverIP = null;
private int serverPort = 5678;
private ConStatus conStatus = ConStatus.DISCONNECTED;
private ChatClientThread clientChatThread = null;
private SendMsgThread sendMsgThread = null;
//views
private EditText edit_serverAddress ;
private EditText edit_msg ;
private Button button_conncet;
private Button button_send;
private TextView text_chat;
private TextView text_status;
//MSG from sockect
private final int MSG_CONNECTING = 0;
private final int MSG_CONNECTED = 1;
private final int MSG_DISCONNECTED = 2;
private final int MSG_RECEIVED = 4;
private final int MSG_ERROR = 5;
//msg from activit self
private final int MSG_SHOW_STATUS = 6;
private final int MSG_UPDATE_CHAT_TEXT = 7;
//msg for user
private final int MSG_USER_SEND_MSG = 100;
private final int MSG_USER_CONNECT = 101;
private final int MSG_USER_STOP = 102;
private String chatText = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_serverAddress = findViewById(R.id.editServer);
edit_msg = findViewById(R.id.editMsg);
button_conncet = findViewById(R.id.button_connect);
button_send = findViewById(R.id.button_send);
text_status = findViewById(R.id.text_status);
text_chat = findViewById(R.id.text_chatContent);
edit_msg.setEnabled(false);
button_send.setEnabled(false);
}
@Override
public void onStop(){
super.onStop();
Log.d(TAG ,"onStop");
}
@Override
public void onDestroy(){
super.onDestroy();
Log.d(TAG ,"onDestroy");
sendStringMsgToActivity(MSG_USER_STOP, "");
}
//button listener
public void onClick_connectToServer(View view) {
if(conStatus == ConStatus.CONNECTING || conStatus == ConStatus.DISCONNECTED){
String uri = edit_serverAddress.getText().toString();
Log.d(TAG, "input address is : " + uri);
if(checkAndSetUri(uri)){
Log.d(TAG, "do connect");
sendStringMsgToActivity(MSG_USER_CONNECT, "");
}else{
text_status.setText("the input is not valid,please try again");
Log.d(TAG, "input address is not valid ");
}
}else{
sendStringMsgToActivity(MSG_USER_STOP, "");
}
}
public void onClick_sendMsg(View view) {
//pass send msg
String str_text = edit_msg.getText().toString();
sendText(str_text);
}
private Handler handlerActivity = new Handler(){
@Override
public void handleMessage(Message msg){
Log.d(TAG ,"handlerActivity handleMessage, what = " + msg.what);
try {
switch (msg.what) {
case MSG_SHOW_STATUS:
text_status.setText(msg.obj.toString());
case MSG_CONNECTING:
text_status.setText(msg.obj.toString());
setConnectStatus(ConStatus.CONNECTING);
sendMsgThread.setSocSource(null);
edit_msg.setEnabled(false);
button_send.setEnabled(false);
break;
case MSG_CONNECTED:
text_status.setText(msg.obj.toString());
button_conncet.setText("Stop");
setConnectStatus(ConStatus.CONNECTED);
sendMsgThread.setSocSource(clientChatThread.socClient);
sendMsgThread.start();
edit_msg.setEnabled(true);
button_send.setEnabled(true);
break;
case MSG_USER_SEND_MSG:
//edit_msg.setText("Test");
break;
case MSG_RECEIVED:
receiveServerText(msg.obj.toString());
break;
case MSG_ERROR:
case MSG_DISCONNECTED:
setConnectStatus(ConStatus.DISCONNECTED);
text_status.setText(msg.obj.toString());
sendMsgThread.setSocSource(null);
button_conncet.setText("Connect");
edit_msg.setEnabled(false);
button_send.setEnabled(false);
break;
case MSG_UPDATE_CHAT_TEXT:
Log.d(TAG, "handlerActivity handleMessage MSG_UPDATE_CHAT_TEXT : " + msg.obj.toString());
text_chat.setText(msg.obj.toString());
break;
case MSG_USER_CONNECT:
clientChatThread = new ChatClientThread();
sendMsgThread = new SendMsgThread();
clientChatThread.setServerAddress(serverIP, serverPort);
clientChatThread.start();
break;
case MSG_USER_STOP:
//need to stop the socket thread
clientChatThread.exit();
sendMsgThread.exit();
button_conncet.setText("Connect");
edit_msg.setEnabled(false);
button_send.setEnabled(false);
break;
}
}catch(Exception e){
e.printStackTrace();
}
}
};
private void sendStringMsgToActivity(int what, String str){
Message msg = handlerActivity.obtainMessage(what);
msg.obj = str;
handlerActivity.sendMessage(msg);
}
public void receiveServerText(String text){
//
text = "server : " + text + "\n";
addChatText(text);
}
public void sendText(String text){
sendStringMsgToActivity(MSG_USER_SEND_MSG, "");
sendMsgThread.sendMsg(text);
//for show
String showText = "client :" + text + "\n";
addChatText(showText);
}
synchronized public void addChatText(String text){
if(chatText == null)
chatText = text;
else
chatText = chatText + text;
if(chatText.length() >= 1000)
chatText = chatText.substring(800);
sendStringMsgToActivity(MSG_UPDATE_CHAT_TEXT, chatText);
}
synchronized public String getChatText(){
return chatText;
}
public void setConnectStatus(ConStatus s){
conStatus = s;
}
public ConStatus getConnectStatus(){
return conStatus ;
}
private boolean checkAndSetUri(String uri) {
String[] ip_port = uri.split(":");
try {
serverIP = InetAddress.getByName(ip_port[0].trim());
if(ip_port.length >= 2 )
serverPort = Integer.parseInt(ip_port[1]);
} catch (UnknownHostException e) {
e.printStackTrace();
serverIP = null;
return false;
}
return true;
}
class SendMsgThread extends Thread{
private BufferedWriter outClient;
private Looper mLooper = null ;
protected Handler mHandlerSend = null;
private String msg_send = null;
public SendMsgThread(){
super("SendMsgThread");
}
private void sendStringMsgToSendThread(int what, String str){
if(mHandlerSend != null) {
Message msg = mHandlerSend.obtainMessage(what);
msg.obj = str;
mHandlerSend.sendMessage(msg);
}
}
private void resetSoc(){
try {
if(outClient != null)
outClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setSocSource(Socket soc) throws IOException {
if(soc != null)
outClient = new BufferedWriter(new OutputStreamWriter(soc.getOutputStream()));
else
outClient = null;
}
public void sendMsg(String msg){
Log.d(TAG, "sendMsg to server: "+ msg);
sendStringMsgToSendThread(MSG_USER_SEND_MSG,msg);
}
public void exit(){
if(mLooper != null){
Log.d(TAG, " SendMsgThread mLooper.quit called");
sendStringMsgToSendThread(MSG_USER_STOP, "");
mLooper.quitSafely();
mLooper = null;
}
}
@Override
public void run(){
Looper.prepare();
mLooper = Looper.myLooper();
mHandlerSend = new Handler(){
public void handleMessage(Message msg){
switch (msg.what){
case MSG_USER_SEND_MSG:
if(outClient != null && msg.obj != null){
try {
msg_send = msg.obj.toString();
Log.d(TAG, "SendMsgThread handleMessage: msg_send = " + msg_send);
if(msg_send != null) {
outClient.write(msg_send);
outClient.newLine();
outClient.flush();
}
} catch (IOException e) {
e.printStackTrace();
resetSoc();
}finally{
}
}
break;
case MSG_USER_STOP:
resetSoc();
break;
}
}
};
Looper.loop();
Log.d(TAG, " SendMsgThread run out");
}
}
public class ChatClientThread extends Thread {
private Socket socClient = null ;
private BufferedReader inClient = null;
private BufferedWriter outClient = null;
private InetAddress serverIP = null;
private int port = 0;
public ChatClientThread(InetAddress ip, int port) {
this();
serverIP = ip;
this.port = port;
}
public ChatClientThread() {
super("chatClientThread");
reset();
}
public void reset(){
socClient = null ;
inClient = null;
outClient = null;
serverIP = null;
}
public void setServerAddress(InetAddress ip, int port){
serverIP = ip;
this.port = port;
}
public void connectToServer() throws IOException {
Log.d(TAG ,"connect to " + serverIP + ":" + port);
sendStringMsgToActivity(MSG_CONNECTING,"connect to " + serverIP + ":" + port );
socClient = new Socket(serverIP, port);
Log.d(TAG ,"connected to " + serverIP + ":" + port);
sendStringMsgToActivity(MSG_CONNECTED,"connected to " + serverIP + ":" + port );
inClient = new BufferedReader(new InputStreamReader(socClient.getInputStream()));
}
public void stopSocket(){
try {
if (socClient != null && socClient.isClosed())
socClient.close();
if (inClient != null )
inClient.close();
if (outClient != null)
outClient.close();
}catch(Exception e){
e.printStackTrace();
}finally {
reset();
}
}
public void exit(){
interrupt();
}
@Override
public void run() {
String msg_test = "I am msg from client ";
int count = 0;
try {
connectToServer();
while(!isInterrupted()) {
// print("want to send msg to server");
//outClient.write("Client : "+ msg_test + count);
// outClient.newLine();
//outClient.flush();
// String msg = msg_test + ",index " +count + "\n";
// outClientStream.write(msg.getBytes());
// outClientStream.flush();
// print("sent over");
//TimeUnit.SECONDS.sleep(2);
String line = inClient.readLine();
// print("receive msg from client" + line);
sendStringMsgToActivity(MSG_RECEIVED, line);
if(line.equals("quit")) {
// print("client request to quit");
break;
}
count++;
}
} catch (Exception e) {
// TODO Auto-generated catch block
sendStringMsgToActivity(MSG_ERROR,"some error happen in socket" );
e.printStackTrace();
}finally {
Log.d(TAG, "ChatClientThread finnally called");
sendStringMsgToActivity(MSG_DISCONNECTED, "chatClientThread finnally called, disconnected");
stopSocket();
}
}
}
}
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_connect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/editServer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingRight="16dp"
android:ems="10"
android:hint="input ip and port"
android:text="172.20.10.3"
android:inputType="textUri" />
<Button
android:id="@+id/button_connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick_connectToServer"
android:text="connect" />
</LinearLayout>
<TextView
android:id="@+id/text_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="not connected" />
<TextView
android:id="@+id/text_chatContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/layout_sendMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/editMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="test"
android:ems="10"
android:inputType="textPersonName" />
<Button
android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick_sendMsg"
android:text="send" />
</LinearLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>