基于Socket的Android聊天室
Posted 叶子8324
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Socket的Android聊天室相关的知识,希望对你有一定的参考价值。
1 基于Socket的android聊天室
Socket通信是网络通信中最常用的技术之一,通过Socket建立的可靠连接,可以让多个终端与服务器保持通信,最典型的应用是建立一个多人聊天程序。本实例使用ServerSocket建立聊天服务器。将服务器端所有的通讯线程保存到一个集合当中,当有用户发来数据,则转发给所有用户,实现聊天室效果。Android端通过使用Socket建立客户端链接,并且在AsyncTask中执行网络读写的任务,将用户输入的内容发送到服务器,并接收服务器发来的数据,显示到界面上。开启多个虚拟机模拟多人聊天效果。
1.1 Socket聊天基本步骤
1,建立socket服务
2,等待连接
3,将建立的连接放在新的线程里
4,由于每个socket客户端连接相互独立,所以他们之间无法通信
5,使用一个类对新建的客户端线程进行管理,然后实现相互通信,管理类要做成单例,保证唯一性,并通过服务类进行转发来实现客户端相互通信
1.2 项目使用说明
1,下载源码 基于Socket的Android聊天室2,将db_chat.sql导入到mysql数据库
3,将SocketChatServer项目导入到Eclipse,配置Tomcat下运行。
修改hibernate配置文件,改成修改成自己的环境
4,将SocketChat项目导入到Eclipse,配置Android环境并编译运行。
1.3 java web服务端
1.3.1 开启socket服务线程
使用Servlet init方法中调用启动线程,并在web.xml配置自启动。就可以在服务启动的时候启动socket服务。
package com.jie.socket.chat;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
/**
* @ClassName: MyServerSocket.java
* @Description: TODO(Socket服务端)
* @author yangjie
* @version V1.0
* @Date 2016年5月23日 下午3:03:16
*/
public class MyServerSocket extends HttpServlet
private static final long serialVersionUID = 1L;
@Override
public void init() throws ServletException
// TODO Auto-generated method stub
new ServerListenerThread().start();// 开启线程
System.out.println("开启socket服务…………………………");
// 在windows cmd下输入
// telnet localhost 12345
// 即可建立socket连接
1.3.2 socket服务监听线程(ServerListenerThread.java)
用于开启socket服务,并进行监听客户端连接
客户端首次接入,传递自己的名称,格式“name:***”
将连接的客户端,传入到客户端管理类中。
package com.jie.socket.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JOptionPane;
/**
* @ClassName: ServerListenerThread.java
* @Description: TODO(ServerSoket监听线程)
* @author yangjie
* @version V1.0
* @Date 2016年5月23日 下午3:38:17
*/
public class ServerListenerThread extends Thread
int i=1001;
@Override
public void run()
// TODO Auto-generated method stub
super.run();
try
ServerSocket serverSocket = new ServerSocket(12345);
// 循环监听连接
while (true)
// 阻塞block
Socket socket = serverSocket.accept();
// 建立连接
// 在浏览器中输入:http://localhost:12345/
// 会弹出提示框,点击确定后断开连接
//JOptionPane.showMessageDialog(null, "有客户端连接到本机");
// 将Socket传递给新的线程,每个socket享受独立的连接
// new ChatSocket(socket).start();//开启chatSocket线程
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream(), "utf-8"));
String line = null;
String name = null;
if ((line = br.readLine())!=null) //接收到客户端数据
if(line.indexOf("name:")!=-1)
name = line.substring(line.indexOf("name:")+5);
System.out.println(name+":连接到本机");
//br.close();//关闭输入流
ChatSocket chatSocket = new ChatSocket(socket, name);
chatSocket.start();
ChatManager.getChatManager().add(chatSocket);
i++;
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
1.3.3 socke客户端线程(ChartSocket.java)
Socket客户端线程,通过该线程类发送和接收信息。
package com.jie.socket.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
/**
* @ClassName: ChatSocket.java
* @Description: TODO(socket客户端线程)
* @author yangjie
* @version V1.0
* @Date 2016年5月23日 下午3:41:13
*/
public class ChatSocket extends Thread
Socket socket;
String sName;
/**
* 构造函数
*/
public ChatSocket(Socket socket, String sName)
// TODO Auto-generated constructor stub
this.socket = socket;
this.sName = sName;
@Override
public void run()
// TODO Auto-generated method stub
// 输入
try
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) // 接收到客户端数据
System.out.println(getsName() + ":" + line);
ChatManager.getChatManager().publish(this, line);
br.close();// 关闭输入流
catch (UnsupportedEncodingException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
public void out(String out)
// TODO Auto-generated method stub
try
socket.getOutputStream().write(out.getBytes("UTF-8"));
catch (UnsupportedEncodingException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
if ("Socket is closed".equals(e.getMessage())) // 对于已经关闭的连接从管理器中删除
System.out.println(e.getMessage());
ChatManager.getChatManager().remove(this);
// e.printStackTrace();
public String getsName()
return sName;
public void setsName(String sName)
this.sName = sName;
1.3.4 客户端管理类(ChatManager.java)
用于管理客户端,保存所有客户端信息,传输客户端发送的信息。
package com.jie.socket.chat;
import java.util.Vector;
/**
* @ClassName: ChatManager.java
* @Description: TODO(socket客户端连接管理类,单例)
* @author yangjie
* @version V1.0
* @Date 2016年5月23日 下午4:25:38
*/
public class ChatManager
private static final ChatManager chatManager = new ChatManager();
private ChatManager()
public static ChatManager getChatManager()
return chatManager;
Vector<ChatSocket> vector = new Vector<ChatSocket>();
/**
* @Title: add
* @Description: TODO(向集合中增加ChatSocket)
* @param chatSocket
* @return: void
* @throws
*/
public void add(ChatSocket chatSocket)
vector.add(chatSocket);
public void remove(ChatSocket chatSocket)
vector.remove(chatSocket);
/**
* @Title: publish
* @Description: TODO(向其他ChatSocket连接发送信息)
* @param chatSocket
* @param out
* @return: void
* @throws
*/
public void publish(ChatSocket chatSocket,String out)
for(int i =0;i<vector.size();i++)
ChatSocket cs = vector.get(i);
if(!cs.equals(chatSocket))//发给不是自己的其他人
cs.out(out+"\\n");
1.3.5 Hibernate工具类
hibernate工具类,用于连接数据库,操作数据库
package com.jie.socket.chart.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
/**
* @ClassName: HibernateUtil.java
* @Description: TODO(Hibernate数据库工具类)
* @author yangjie
* @version V1.0
* @Date 2016-5-16 上午11:42:11
*/
@SuppressWarnings("deprecation")
public class HibernateUtil
private static SessionFactory sessionFacotry = buildSessionFactory();
private static SessionFactory buildSessionFactory()
// TODO Auto-generated method stub
try
Configuration cfg = new Configuration();
cfg.configure();
ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
cfg.getProperties()).buildServiceRegistry();
return cfg.buildSessionFactory(sr);
catch (Exception e)
return null;
public static SessionFactory getSessionFacotry()
return sessionFacotry;
1.3.6 用户实体
用于保存用户信息,关联数据库中的用户表
package com.jie.socket.chart.vo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
/**
* @ClassName: User.java
* @Description: TODO(用户实体类)
* @author yangjie
* @version V1.0
* @Date 2016-5-24 下午9:17:10
*/
@Entity
@Table(name = "User")
public class User
@Id
@GeneratedValue(generator = "userIdGenerator")
@GenericGenerator(name = "userIdGenerator", strategy = "uuid")
private String id;
@Column
private String name;
@Column
private String password;
public String getId()
return id;
public void setId(String id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
1.3.7 用户登录Servlet
处理用户登陆验证,通过数据库验证。
package com.jie.socket.chat;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import com.jie.socket.chat.util.HibernateUtil;
import com.jie.socket.chat.vo.User;
/**
* @ClassName: ChatLogin.java
* @Description: TODO(登陆)
* @author yangjie
* @version V1.0
* @Date 2016-5-16 上午11:20:16
*/
public class ChatLogin extends HttpServlet
private static final long serialVersionUID = 1L;
public ChatLogin()
super();
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
doPost(request, response);
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
//int uuid = Integer.parseInt(request.getParameter("uuid"));
String name = request.getParameter("name");
String password = request.getParameter("password");
//System.out.println(uuid);
System.out.println(name);
System.out.println(password);
//是否登陆
boolean islogin = false;
if (!islogin)
// 查询用户表,验证登录
SessionFactory sf = HibernateUtil.getSessionFacotry();
Session session = sf.openSession();
Criteria criteria = session.createCriteria(User.class);
//criteria.add(Restrictions.eq("uuid", uuid));
criteria.add(Restrictions.eq("name", name));//按照姓名查找
criteria.add(Restrictions.eq("password", password));//按照密码查找
List<User> result = criteria.list();
if (result.size() ==1) //登陆成功
System.out.println(name+",登陆成功");
islogin = true;
else//登录失败
System.out.println(password+",登陆失败");
session.close();
sf = null;
PrintWriter out = response.getWriter();
out.print(islogin);//传递登陆是否成功
out.flush();
out.close();
1.3.8 hibernate.cfg.xml配置文件
配置数据库信息,实体类信息。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://192.168.0.99:3306/jie-db</property>
<property name="connection.username">root</property>
<property name="connection.password">bonc123,</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- 方言,针对不同的数据库不一样 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- 打印sql语句 -->
<property name="show_sql">true</property>
<!-- 时候让hibernate自动生成建表语句 -->
<property name="hbm2ddl.auto">update</property>
<!-- xml实体类映射文件 -->
<!-- <mapping resource="com/jie/hibernate/po/Student.hbm.xml"/> -->
<!-- Annotation实体类映射文件 -->
<mapping class="com.jie.socket.chat.vo.User" />
</session-factory>
</hibernate-configuration>
1.3.9 web.xml
配置servlet登陆类,自启动socket服务。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name></display-name>
<servlet>
<description>自启动servlet,用于开启socket服务</description>
<servlet-name>myServerSocket</servlet-name>
<servlet-class>com.jie.socket.chat.MyServerSocket</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<description>手机登陆</description>
<servlet-name>chatLogin</servlet-name>
<servlet-class>com.jie.socket.chat.ChatLogin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>chatLogin</servlet-name>
<url-pattern>/chatLogin</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
1.4 Android手机端
基于socket技术,通过网络端开启SocketServer服务,手机端登陆并连接SocketServer服务,通过socket客户端将消息发送到服务端,服务端分发给连接到该服务的所有客户端。实现手机群聊的效果。
1.4.1 用户信息类
通过SharedPreferences将用户名称存储到手机中。
package com.jie.socket.chat.info;
import java.io.Serializable;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
public class UserInfo implements Serializable
private static final long serialVersionUID = 1L;
private static final String PREFERENCES_TAG = "com.jie.socket.chart";
private static UserInfo instance;
private String name = "";
public static UserInfo getInstance()
if (instance == null)
synchronized (UserInfo.class)
if (instance == null)
instance = new UserInfo();
return instance;
public static void saveName(Context context)
SharedPreferences mySharedPreferences = context.getSharedPreferences(
PREFERENCES_TAG, Activity.MODE_PRIVATE);
SharedPreferences.Editor edit = mySharedPreferences.edit();
edit.putString("name", getInstance().getName());
edit.commit();
public static String readName(Context context)
SharedPreferences mySharedPreferences = context.getSharedPreferences(
PREFERENCES_TAG, Activity.MODE_PRIVATE);
String mName = mySharedPreferences.getString("name", "");
getInstance().setName(mName);
return mName;
public static void readAll(Context context)
readName(context);
public void cleanUserInfo(Context context)
SharedPreferences mySharedPreferences = context.getSharedPreferences(
PREFERENCES_TAG, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = mySharedPreferences.edit();
editor.remove("name");
editor.commit();
public String getName()
return name;
public void setName(String name)
this.name = name;
1.4.2 activity_main.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"
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="com.jie.socket.chat.MainActivity" >
</RelativeLayout>
1.4.3 MainActivity入口类
MainActivity入口,监测用户是否登陆状况,判断进入主界面还是进入登陆界面
package com.jie.socket.chat;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.jie.socket.chat.info.UserInfo;
/**
* @ClassName: MainActivity.java
* @Description: TODO(Activity入口,监测用户是否登陆状况,判断进入主界面还是进入登陆界面)
* @author yangjie
* @version V1.0
* @Date 2016年5月25日 下午8:35:48
*/
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkLogin();
/**
* @Title: checkLogin
* @Description: TODO(监测是否登陆)
* @return: void
* @throws
*/
public void checkLogin()
// TODO Auto-generated method stub
UserInfo.readAll(getApplicationContext());
String name = UserInfo.getInstance().getName();
System.out.println("username:" + name);
if (name != null && !"".equals(name))
gotoNext();
else
gotoLogin();
public void gotoLogin()
Intent intent = new Intent();
intent.setClass(MainActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
private void gotoNext()
Intent intent = new Intent();
intent.setClass(MainActivity.this, ChatActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
1.4.4 activity_chat.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"
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="com.jie.socket.chat.ChatActivity" >
<LinearLayout
android:id="@+id/layout_link"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/et_ip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:hint="请输入连接"
android:text="192.168.0.199" />
<Button
android:id="@+id/btn_connect"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="2"
android:background="@drawable/btn_selector"
android:text="连接" />
</LinearLayout>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/layout_link"
android:hint="消息" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical" >
<EditText
android:id="@+id/et_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入发送内容" />
<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/btn_selector"
android:text="发送" />
</LinearLayout>
</RelativeLayout>
1.4.5 ChatActivity聊天类
通过socket连接服务器端,建立连接,然后通过socket接收和发送信息。
package com.jie.socket.chat;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.alibaba.fastjson.JSONObject;
import com.jie.socket.chat.info.UserInfo;
/**
* @ClassName: ChatActivity.java
* @Description: TODO(聊天)
* @author yangjie
* @version V1.0
* @Date 2016年5月25日 下午7:47:00
*/
public class ChatActivity extends BaseActivity
EditText et_ip;
EditText et_msg;
TextView tv_conent;
Button btn_send;
Button btn_connect;
Socket socket;
BufferedWriter writer;
BufferedReader reader;
String TAG = "Socket Chart";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
et_ip = (EditText) findViewById(R.id.et_ip);
et_msg = (EditText) findViewById(R.id.et_msg);
tv_conent = (TextView) findViewById(R.id.tv_content);
btn_connect = (Button) findViewById(R.id.btn_connect);
btn_send = (Button) findViewById(R.id.btn_send);
btn_send.setEnabled(false);
et_msg.setEnabled(false);
eventListener();
private void eventListener()
// TODO Auto-generated method stub
btn_connect.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
connnet();
);
btn_send.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
send();
);
et_msg.setOnKeyListener(onKey);
StringBuffer text = new StringBuffer();
/**
* @Title: connnet
* @Description: TODO(连接)
* @return: void
* @throws
*/
private void connnet()
// TODO Auto-generated method stub
read.execute();
/**
* @Title: send
* @Description: TODO(发送消息)
* @return: void
* @throws
*/
private void send()
// TODO Auto-generated method stub
try
String msg = et_msg.getText().toString();
if (msg != null && !"".equals(msg))
text.append(name + ":" + msg + "\\n");
tv_conent.setText(text);
// 传递给sokect服务,json数据name:1212,msg:'121212'
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("msg", msg);
writer.write(jsonObject.toString() + "\\n");
writer.flush();// 刷新缓冲区,强制输出
Log.i(TAG, msg);
et_msg.setText("");
else
showToast("请输入发送内容");
catch (NullPointerException excNull)
Log.i(TAG, "writer error:" + "空指针异常");
showToast("请点击连接,连接到服务器");
catch (Exception e)
// TODO Auto-generated catch block
Log.i(TAG, "Error:" + e.getMessage());
e.printStackTrace();
@SuppressLint("ShowToast")
public void showToast(String msg)
Toast.makeText(getApplicationContext(), msg, 1000).show();
OnKeyListener onKey = new OnKeyListener() // 回车键监听
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
// 回车键,并且为鼠标按下,防止按下回车键两次调用
if (keyCode == KeyEvent.KEYCODE_ENTER
&& event.getAction() == KeyEvent.ACTION_DOWN)
Log.i(TAG, "回车键:" + keyCode);
send();
return true;
return false;
;
OutputStreamWriter outputStreamWriter;
InputStreamReader inputStreamReader;
AsyncTask<Void, String, Void> read = new AsyncTask<Void, String, Void>()
@Override
protected Void doInBackground(Void... params)
// TODO Auto-generated method stub
try
socket = new Socket(et_ip.getText().toString().trim(), 12345);
outputStreamWriter = new OutputStreamWriter(
socket.getOutputStream());
inputStreamReader = new InputStreamReader(
socket.getInputStream());
writer = new BufferedWriter(outputStreamWriter);
reader = new BufferedReader(inputStreamReader);
publishProgress("@success");
catch (UnknownHostException e)
// TODO Auto-generated catch block
Log.i("socket", "连接失败");
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
// showToast("连接失败");
Log.i("socket", "连接失败");
String line;
// 异步线程未关闭
if (!isCancelled())
while (true)
try
if ((line = reader.readLine()) != null)
publishProgress(line);
catch (IOException e)
// TODO Auto-generated catch block
if ("Socket closed".equals(e.getMessage()))
Log.i(TAG, "连接已关闭");
else
e.printStackTrace();
break;
return null;
@Override
protected void onProgressUpdate(String... values)
// TODO Auto-generated method stub
if (values[0] != null && !"".equals(values[0]))
if (values[0] == "@success")
// text.append(values[0]);
btn_connect.setEnabled(false);
Log.i(TAG, "连接服务器成功!");
tv_conent.setText("连接服务器成功!");
btn_send.setEnabled(true);
et_msg.setEnabled(true);
name = UserInfo.readName(getApplicationContext());
if (name != null && !"".equals(name))
;
Log.i(TAG, "name:" + name);
try
writer.write("name:" + name + "\\n");
writer.flush();// 强制输出
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
else
JSONObject obj = JSONObject.parseObject(values[0]);// 将json字符串转换为对象
String cName = obj.getString("name");
String cMsg = obj.getString("msg");
text.append(cName + ":" + cMsg + "\\n");
Log.i(TAG, values[0]);
tv_conent.setText(text);
;
@Override
protected void onDestroy()
// TODO Auto-generated method stub
super.onDestroy();
// Log.i(TAG, "socket != null:"+(socket != null)
// +"----socket.isClosed():"+(!socket.isClosed()));
if (socket != null && !socket.isClosed())
Log.i(TAG, "关闭连接");
try
read.cancel(true);// 线程关闭
socket.close();
reader.close();
writer.close();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
// 关闭连接
1.4.6 基础Activity
用于设置Activity公用的字段和方法。
package com.jie.socket.chat;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.widget.Toast;
import com.jie.socket.chat.info.UserInfo;
public class BaseActivity extends Activity
String name;
@Override
protected void onCreate(Bundle savedInstanceState)
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
initDatas();
public void findViews()
public void initDatas()
name = UserInfo.readName(getApplicationContext());
public void clickEvents()
@Override
protected void onDestroy()
// TODO Auto-generated method stub
super.onDestroy();
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
// TODO Auto-generated method stub
return super.onKeyDown(keyCode, event);
@Override
protected void onResume()
// TODO Auto-generated method stub
super.onResume();
@Override
protected void onPause()
// TODO Auto-generated method stub
super.onPause();
@Override
public void onBackPressed()
super.onBackPressed();
public void showToast(CharSequence message)
if (message != null && !"".equals(message))
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT)
.show();
else
Toast.makeText(getApplicationContext(), "连接超时,请检查网络",
Toast.LENGTH_SHORT).show();
1.4.7 activity_login.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:layout_gravity="center"
android:background="@drawable/gb_background"
android:gravity="center"
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="com.jie.socket.chat.LoginActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="用户名:"
android:textSize="18px" />
<EditText
android:id="@+id/userName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:textSize="18px" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="密 码:"
android:textSize="18px" />
<EditText
android:id="@+id/userPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:password="true"
android:textSize="18px" />
</LinearLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="@drawable/btn_selector"
android:text="登陆" />
</LinearLayout>
1.4.8 LoginActivity登陆类
package com.jie.socket.chat;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import com.jie.socket.chat.info.UserInfo;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
public class LoginActivity extends BaseActivity
EditText et_userName;
EditText et_userPassword;
Button btn_login;
String name;
String password;
protected String httpUrl = "http://192.168.0.199:8080/SocketChatServer/chatLogin";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
et_userName = (EditText) findViewById(R.id.userName);
et_userPassword = (EditText) findViewById(R.id.userPassword);
btn_login = (Button) findViewById(R.id.btn_login);
btn_login.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// TODO Auto-generated method stub
name = et_userName.getText().toString();
password = et_userPassword.getText().toString();
if (!"".equals(name) && !"".equals(password))
HttpUtils http = new HttpUtils();
RequestParams params = new RequestParams();
params.addBodyParameter("name", name);
params.addBodyParameter("password", password);
http.send(HttpMethod.POST, httpUrl, params,
new RequestCallBack<String>()
@Override
public void onFailure(HttpException arg0,
String arg1)
// TODO Auto-generated method stub
Log.i("http.send", "failuer");
@Override
public void onSuccess(ResponseInfo<String> arg0)
// TODO Auto-generated method stub
String isLogin = arg0.result;
if ("true".equals(isLogin)) // 登陆成功
Intent intent = new Intent();
intent.setClass(LoginActivity.this,
ChatActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
Log.i("http.send", "success" + isLogin);
UserInfo.getInstance().setName(name);
UserInfo.saveName(getApplicationContext());
else
showToast("用户名或密码错误");
);
);
1.5 源码下载
基于Socket的Android聊天室
以上是关于基于Socket的Android聊天室的主要内容,如果未能解决你的问题,请参考以下文章