Android之Socket群组聊天
在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息
- 贴一下Android客户端的源码 -
MainActivity.Java
- package com.zml.chatproject;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.support.v7.app.AppCompatActivity;
- import android.text.Editable;
- import android.text.TextUtils;
- import android.text.TextWatcher;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.WindowManager;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ListView;
- import android.widget.Toast;
- import com.google.gson.Gson;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author 郑明亮 @email 1072307340@qq.com
- * @Time:2016/4/20 14:25
- * @version 1.0
- * TODO
- */
- public class MainActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher {
- private static final String TAG = "MainActivity";
- public static final int SENDMESSAGE = 0x004;
- public static final String name = System.currentTimeMillis()+"";
- List<Msg> list ;
- ListView mListView;
- EditText edit;
- Button bt_send;
- Socket socket;
- public static final int SHOWMSG = 0x003;
- private DataInputStream mDataInputStream = null;
- private DataOutputStream mDataOutputStream = null;
- private boolean Conneted = false;
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- Log.i(TAG,"执行到handle");
- if (msg.what == SENDMESSAGE) {
- Msg xiaoxi = (Msg) msg.obj;
- Log.i(TAG,"handler:"+xiaoxi.toString());
- list.add(xiaoxi);
- //设置适配器
- mListView.setAdapter(new MyAdapter(MainActivity.this, list));
- mListView.setSelection(mListView.getCount()-1);
- }
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mListView = (ListView) findViewById(R.id.listView);
- edit = (EditText) findViewById(R.id.et_edit);
- edit.addTextChangedListener(this);
- bt_send = (Button) findViewById(R.id.bt_send);
- bt_send.setOnClickListener(this);
- list = new ArrayList<>();
- new AsyncTask<Void,Void,String>(){
- @Override
- protected String doInBackground(Void... params) {
- try {
- socket = new Socket("172.18.40.182", 9999);
- // socket = new Socket("115.28.167.152", 9999);
- connect();
- ClientThread thread = new ClientThread();
- thread.run();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- }.execute();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (event.getAction()){
- case KeyEvent.KEYCODE_HOME:
- Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
- Log.i(TAG,"KeyEvent.KEYCODE_HOME"+KeyEvent.KEYCODE_HOME);
- break;
- case KeyEvent.KEYCODE_MOVE_HOME:
- Toast.makeText(MainActivity.this,"就是不让你退出,O(∩_∩)O哈哈哈~",Toast.LENGTH_LONG).show();
- Log.i(TAG,"KeyEvent.KEYCODE_MOVE_HOME"+KeyEvent.KEYCODE_MOVE_HOME);
- break;
- }
- return true;
- }
- @Override
- public void onAttachedToWindow()
- { // TODO Auto-generated method stub
- this.getWindow().setType(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- super.onAttachedToWindow();
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()){
- case R.id.bt_send:
- String show = edit.getText().toString().trim();
- if (TextUtils.isEmpty(show)){
- }else {
- edit.setText("");
- Msg msg = new Msg();
- msg.setFlag(Msg.TO);
- msg.setMsg(show);
- msg.setUsername(name);
- list.add(msg);
- mListView.setAdapter(new MyAdapter(MainActivity.this,list));
- mListView.setSelection(mListView.getCount()-1);
- try {if (mDataOutputStream==null){
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- }
- Gson gson = new Gson();
- show = gson.toJson(msg);
- mDataOutputStream.writeUTF(show);
- mDataOutputStream.flush();
- Log.i(TAG,"发送成功:"+show);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- break;
- }
- }
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- bt_send.setEnabled(false);
- }
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (s.length()>0){
- bt_send.setEnabled(true);
- }
- }
- @Override
- public void afterTextChanged(Editable s) {
- }
- /**
- * 开启线程,接收消息
- */
- private class ClientThread implements Runnable {
- @Override
- public void run() {
- while (Conneted) {
- try {
- String str = mDataInputStream.readUTF();
- Log.i(TAG,"子线程得到数据:"+str);
- Gson gson = new Gson();
- Msg msg = gson.fromJson(str,Msg.class);
- msg.setFlag(Msg.FROM);
- Message message = mHandler.obtainMessage();
- message.what = SENDMESSAGE;
- message.obj = msg;
- mHandler.sendMessage(message);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 打开连接
- */
- public void connect() {
- try {
- mDataInputStream = new DataInputStream(socket.getInputStream());
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- if (socket.isConnected()){
- Log.i(TAG, "连接上了");
- }else {
- Log.i(TAG, "连接失败");
- }
- Conneted = true;
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /**
- * 断开与服务器的连接
- */
- public void disconnect() {
- try {
- mDataInputStream.close();
- mDataOutputStream.close();
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- disconnect();
- }
- }
Msg.java 消息实体类
- package com.zml.chatproject;
- /**
- * Created by bri on 2016/4/16.
- */
- /**
- * 消息实体类
- */
- public class Msg {
- public static final int FROM = 0x001;
- public static final int TO = 0x002;
- /**
- * 发送聊天消息
- */
- private String msg;
- /**
- * 标识符,表示是发送方还是接收方
- */
- private int flag;
- /**
- * 用户名
- */
- private String username;
- @Override
- public String toString() {
- return "Msg{" +
- "msg='" + msg + '\\'' +
- ", flag=" + flag +
- ", username='" + username + '\\'' +
- '}';
- }
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- public int getFlag() {
- return flag;
- }
- public void setFlag(int flag) {
- this.flag = flag;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- }
MyAdapter 数据适配器
- package com.zml.chatproject;
- import android.content.Context;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListAdapter;
- import android.widget.TextView;
- import java.util.List;
- /**
- * Created by bri on 2016/4/17.
- */
- public class MyAdapter extends BaseAdapter implements ListAdapter {
- private static final String TAG = "MyAdapter";
- Context context;
- List<Msg> message;
- public MyAdapter(Context context, List<Msg> message) {
- this.context = context;
- this.message = message;
- }
- @Override
- public int getCount() {
- return message.size();
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null){
- convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
- }
- TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
- TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
- // tv_from.setText(message.getMsg());
- Log.i(TAG,"接收成功"+message.get(position).getMsg());
- if (message.get(position).getFlag()==(Msg.FROM)){
- if (message.get(position).getUsername().equals(MainActivity.name)){
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.GONE);}
- else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
- tv_from.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.VISIBLE);
- tv_to.setVisibility(View.GONE);}
- // Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- }if (message.get(position).getFlag()==(Msg.TO)){
- // Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
- tv_to.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.VISIBLE);
- }
- return convertView;
- }
- }
ViewHoder 一个超实用的通用ViewHoder类
- package com.zml.chatproject;
- import android.content.Context;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListAdapter;
- import android.widget.TextView;
- import java.util.List;
- /**
- * Created by bri on 2016/4/17.
- */
- public class MyAdapter extends BaseAdapter implements ListAdapter {
- private static final String TAG = "MyAdapter";
- Context context;
- List<Msg> message;
- public MyAdapter(Context context, List<Msg> message) {
- this.context = context;
- this.message = message;
- }
- @Override
- public int getCount() {
- return message.size();
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null){
- convertView = LayoutInflater.from(context).inflate(R.layout.activity_main_item,null);
- }
- TextView tv_from = ViewHolder.get(convertView,R.id.tv_chatting_from);
- TextView tv_to = ViewHolder.get(convertView,R.id.tv_chatting_to);
- // tv_from.setText(message.getMsg());
- Log.i(TAG,"接收成功"+message.get(position).getMsg());
- if (message.get(position).getFlag()==(Msg.FROM)){
- if (message.get(position).getUsername().equals(MainActivity.name)){
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.GONE);}
- else { Log.i(TAG,"接收成功FROM"+message.get(position).getMsg());
- tv_from.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.VISIBLE);
- tv_to.setVisibility(View.GONE);}
- // Toast.makeText(context,"from:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- }if (message.get(position).getFlag()==(Msg.TO)){
- // Toast.makeText(context,"to:"+message.get(position).getMsg(),Toast.LENGTH_LONG).show();
- Log.i(TAG,"接收成功TO"+message.get(position).getMsg());
- tv_to.setText(message.get(position).getMsg());
- tv_from.setVisibility(View.GONE);
- tv_to.setVisibility(View.VISIBLE);
- }
- return convertView;
- }
- }
- 好了,客户端的源码贴完了,接下来服务器端的源码就比较简单了
Client.java 重写一个子线程
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- /**
- * @author 郑明亮
- * @Time:2016年4月16日 下午9:01:53
- * @version 1.0
- */
- public class Client implements Runnable {
- Socket socket;
- List<Client> clients ;
- public static final int SHOWMSG = 0x003;
- private DataInputStream mDataInputStream = null;
- private DataOutputStream mDataOutputStream = null;
- private boolean Conneted = false;
- public Client(Socket socket){
- this.socket = socket;
- try {
- mDataInputStream = new DataInputStream(socket.getInputStream());
- mDataOutputStream = new DataOutputStream(socket.getOutputStream());
- Conneted = true;
- clients =new ArrayList<Client>();
- } catch (IOException e) {
- e.printStackTrace();
- }
- };
- /**
- * 发送消息
- */
- public void send(String string){
- try {
- mDataOutputStream.writeUTF(string);//向输入流中写入数据
- System.out.println("向输入流中写入数据");
- } catch (IOException e) {
- e.printStackTrace();
- // Server.clients.remove(this);//出错时,客户端可能已断线,移除当前客户端
- System.out.println("出错时,客户端可能已断线,移除当前客户端");
- }
- }
- @Override
- public void run() {
- while(Conneted){
- try {
- System.out.println("连接成功!");
- //读取数据
- String str = mDataInputStream.readUTF();
- clients = Server.clients;
- synchronized (clients) {
- Iterator<Client> iterator =clients.iterator();
- while (iterator.hasNext()) {
- Client client = iterator.next();
- //将读取的数据发送回去
- System.out.println("将读取的数据发送回去"+str);
- client.send(str);
- }
- // Conneted = false;
- }
- } catch (IOException e) {
- e.printStackTrace();
- Server.clients.remove(this);
- System.out.println("线程出现异常");
- }finally{
- // try {
- //// mDataOutputStream.close();
- //// mDataInputStream.close();
- // } catch (IOException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- }
- }
- }
- }
Server 服务器端,先运行起它来,再去部署客户端即可
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- /**
- * @author 郑明亮
- * @Time:2016年4月16日 下午9:01:43
- * @version 1.0
- */
- public class Server {
- static boolean started = false;
- public static List<Client> clients = new ArrayList<>();
- public static void main(String a[]){
- try {
- ServerSocket serverSocket = new ServerSocket(9999);
- System.out.println("开启服务,等待监听");
- started = true;
- while (started) {
- System.out.println("开始监听");
- Socket socket = serverSocket.accept();
- Client client = new Client(socket);
- new Thread(client).start();
- clients.add(client);
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
Android之Socket群组聊天的更多相关文章
- Android 内置群组,联系人
这样一个需求,手机第一次启动的时候,需要内置一个群组,并且里面有给定的联系人信息, 本来打算写双进程守护的,结果昨天接到一个这样的任务,就先把它做了,发现里面有些操作数据库的东西还是值得看一下. 首先 ...
- vue-cli3.0 Typescript 项目集成环信WebIM 群组聊天
项目背景 环信webim 官方没有vue版本的,自己就根据sdk重写了个vue版本的,只实现了基础的 登录 群组功能,其他的可以根据需要参考官方文档,添加相应的功能. 环信webim SDK相关文档: ...
- ASP.NET SignalR 系列(五)之群组推送
在上一章介绍了 一对一推送的方式,这章重点介绍下群组推送和多人推送 群组主要就是用到了方法:Groups.Add(Context.ConnectionId, groupName); 将不同的连接id加 ...
- nodejs之socket.io 私发消息和选择群组发消息
写在前面:其实有的时候忙碌是好的,比如忙碌起来的自己手机可以一天耗费掉只有20%的电,忙碌的自己很专心于一件事情,但是忙碌不等于过度疲劳,本周忙碌有点上脑,迷糊了一天,都在补觉,还是要去平衡下自己一天 ...
- Android 基于Socket的聊天应用(二)
很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的 ...
- java ssm 后台框架平台 项目源码 websocket即时聊天发图片文字 好友群组 SSM源码
官网 http://www.fhadmin.org/D 集成安全权限框架shiro Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安全,更可靠E ...
- Activiti6.0 工作流引擎 websocket即时聊天发图片文字 好友群组 SSM源码
即时通讯:支持好友,群组,发图片.文件,消息声音提醒,离线消息,保留聊天记录 (即时聊天功能支持手机端,详情下面有截图) 工作流模块---------------------------------- ...
- java工作流引擎 Activiti6.0 websocket 即时聊天发图片文字 好友群组 SSM源码
时通讯:支持好友,群组,发图片.文件,消息声音提醒,离线消息,保留聊天记录 工作流模块--------------------------------------------------------- ...
- Android/iOS微信6.3.5同时发布更新 支持群视频聊天、群公告
下午微信6.3.5发布更新,新版最大变化就是支持群视频聊天,又一次向手机QQ靠拢.在群管理方面,支持发布群公告,支持群主转让给其他群成员,同样都是QQ玩剩下的功能.另外,新版支持微信运动查看步数图表. ...
随机推荐
- 编程实现linux下的shell
/************************************************************************* > File Name: Kris_shel ...
- poj 3662(经典最短路)
题目链接:http://poj.org/problem?id=3662 思路:这题较多的有两种做法: 方法1:二分枚举最大边长limit,如果图中的边大于limit,则将图中的边当作1,表示免费使用一 ...
- spring mvc 基于注解的使用总结
本文转自http://blog.csdn.net/lufeng20/article/details/7598801 概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Sprin ...
- MongoDB 管理工具:Robomongo
http://www.open-open.com/lib/view/open1383029577546.html
- lintcode:格雷编码
格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个二进制的差异. 给定一个非负整数 n ,表示该代码中所有二进制的总数,请找出其格雷编码顺序.一个格雷编码顺序必须以 0 开始, ...
- lintcode:等价二叉树
等价二叉树 检查两棵二叉树是否等价.等价的意思是说,首先两棵二叉树必须拥有相同的结构,并且每个对应位置上的节点上的数都相等. 样例 1 1 / \ / \ 2 2 and 2 2 / / 4 4 就是 ...
- 【转】SIP初步
1.什么是SIP SIP(会话发起协议)属于IP应用层协议,用于在IP网上为用户提供会话应用.会话(Session)指两方或多方用户之间的语音.视频.及其他媒体形式的通信,具体可能是IP电话.会议.即 ...
- 解决IIS应用程序池DefaultAppPool关闭超时错误
错误系统日志: 为应用程序池“DefaultAppPool”提供服务的进程关闭时间超过了限制.进程 ID 是“3060”. 有关更多信息,请参阅在http://go.microsoft.com/fwl ...
- iOS开发--3D Touch的基本使用
1.桌面快捷菜单项 效果如图: 桌面快捷菜单 点击之后的效果如图: 点击桌面快捷菜单的效果 接下来看下具体实现:1).在-application:didFinishLaunchingWithOptio ...
- VCL定义和使用CM_Message的原因(主要是内部控制,同时可简化参数传递,还可截住消息,统一走消息路线,还可省内存)
内部控制是指,做了某些操作后产生某些效果,但是Windows系统本身不提供这样的消息,应此不得不自定义.比如父窗口改变了字体,那么所有子窗口也都应该改变字体,至少也得通知一下它们,让子控件自己决定是否 ...