转载请注明本文出自Cym的博客(http://blog.youkuaiyun.com/cym492224103),谢谢支持!
山寨版微信(下)
昨天 我们完成 上线列表刷新。
聊天:
消息:
用户发送:
只需要显示客户端的消息。
一个人可以和多个人聊天。
聊天的内容存放在哪里?数据库 内存 文件
你的数据是那个类来操作。
ThreadClient
HashMap<key,value> value List<MessageInfo>
消息有两种来源:
1 自己发
2 别人发过来
唯一标示:ip+":"+port
服务器消息的转发工作
处理消息有两种情况:
1 没有聊天,我还在MainActivity
2 在聊天
原理图:
Server:
public class WeiXinServer {
//记录所有的客户端
publicstatic List<ThreadClient> list =new ArrayList<ThreadClient>();
/**
* 启动服务
* @throws Exception
*/
publicvoid start() throws Exception{
final ServerSocket serverSocket = newServerSocket(8809);
System.out.println(serverSocket.getLocalPort());
System.out.println(serverSocket.getInetAddress().getHostAddress());
new Thread(new Runnable() {
@Override
publicvoid run() {
// TODO Auto-generated method stub
while(true){
try{
//客户端
Socket socket = serverSocket.accept();
ThreadClient client = newThreadClient(socket);
client.start();
System.out.println("ip:"+client.ip+",port:"+client.port);
//通知之前已上线的人
/**
*迭代所有的客户端:发送消息给每个客户端
*c:之前上线的用户
*
*/
for(ThreadClient c:list){
Stringmsg = "refresh@"+client.ip+"@"+client.port;
c.sendMessage(msg);
}
//自己的上线之后,也要知道之前上线的人
//client就是自己
for(ThreadClient c:list){
Stringmsg = "refresh@"+c.ip+"@"+c.port;
client.sendMessage(msg);
}
list.add(client);
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
} catch (Exception e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
publicstatic void main(String[] args) {
// TODO Auto-generated method stub
start();
}
}
ThreadClient:
public class ThreadClient extends Thread {
//ip地址
publicString ip;
//端口号
publicint port;
//客户端套接字
publicSocket socket;
//输入流
publicInputStream is;
//输出流
publicOutputStream os;
publicPrintWriter pw;
publicBufferedReader br;
publicThreadClient(Socket socket) {
super();
try {
this.socket= socket;
this.ip= socket.getInetAddress().getHostAddress();
this.port= socket.getPort();
this.is= socket.getInputStream();
this.br= new BufferedReader(new InputStreamReader(is));
this.os= socket.getOutputStream();
this.pw= new PrintWriter(os);
} catch (Exception e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
//发送消息
publicvoid sendMessage(String msg){
pw.println(msg);
pw.flush();
}
@Override
publicvoid run() {
// TODO Auto-generated method stub
super.run();
while(true){
try{
String message = br.readLine();
if(message != null){
System.out.println("服务器得到消息"+message);
StringTokenizertoken = new StringTokenizer(message, "@");
Stringcmd = token.nextToken();
//消息
if("text".equals(cmd)){
String ip1 = token.nextToken();
int port1 =Integer.parseInt(token.nextToken());
String content = token.nextToken();
//查找要发送的目标
//迭代服务器所有的Socket
List<ThreadClient> list =WeiXinServer.list;
for(ThreadClient client:list){
if(ip1.equals(client.ip)&& port1==client.port){
//拼接消息text@ip@port@content
String msg ="text@"+ip+"@"+port+"@"+content;
client.sendMessage(msg);
System.out.println(msg);
break;
}
}
}
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
客户端:Adapter:
public class MyChatMessageAdapter extendsBaseAdapter {
privateContext context;
privateList<MessageInfo> infos;
privateLayoutInflater mInflater;
publicMyChatMessageAdapter(Context context, List<MessageInfo> infos) {
super();
this.context = context;
this.infos = infos;
mInflater = LayoutInflater.from(context);
}
@Override
publicint getCount() {
// TODO Auto-generated method stub
return infos.size();
}
@Override
publicObject getItem(int position) {
// TODO Auto-generated method stub
return infos.get(position);
}
@Override
publiclong getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
publicView getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = null;
ViewHolder holder = null;
if(convertView != null){
view= convertView;
holder= (ViewHolder) view.getTag();
}else{
view= mInflater.inflate(R.layout.chating_item, null);
holder= new ViewHolder();
holder.tv_message= (TextView) view.findViewById(R.id.tv_message);
view.setTag(holder);
}
MessageInfo info = infos.get(position);
holder.tv_message.setText(info.content);
return view;
}
privateclass ViewHolder{
TextView tv_message;
}
}
public class MyUserAdapter extends BaseAdapter{
privateList<UserInfo> infos;
privateContext context;
privateLayoutInflater mInflater;
publicMyUserAdapter(List<UserInfo> infos, Context context) {
super();
this.infos = infos;
this.context = context;
mInflater = LayoutInflater.from(context);
}
@Override
publicint getCount() {
// TODO Auto-generated method stub
return infos.size();
}
@Override
publicObject getItem(int position) {
// TODO Auto-generated method stub
return infos.get(position);
}
@Override
publiclong getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
publicView getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = null;
ViewHolder holder = null;
if(convertView != null){
view= convertView;
holder= (ViewHolder) view.getTag();
}else{
view= mInflater.inflate(R.layout.user_item, null);
holder= new ViewHolder();
holder.tv_ip= (TextView) view.findViewById(R.id.tv_ip);
holder.tv_port= (TextView) view.findViewById(R.id.tv_port);
holder.tv_isnew= (TextView) view.findViewById(R.id.tv_isnew);
view.setTag(holder);
}
//得到数据
UserInfo info = infos.get(position);
holder.tv_ip.setText(info.ip);
holder.tv_port.setText(info.port+"");
if(info.isNew){
holder.tv_isnew.setVisibility(View.VISIBLE);
}else{
holder.tv_isnew.setVisibility(View.INVISIBLE);
}
return view;
}
privateclass ViewHolder{
TextView tv_ip;
TextView tv_port;
TextView tv_isnew;
}
}
Client:
public class ThreadClient extends Thread {
//记录用户的信息
publicList<UserInfo> userInfos = new ArrayList<UserInfo>();
//存放所有的消息
publicHashMap<String,List<MessageInfo>> messages = new HashMap<String,List<MessageInfo>>();
publicSocket socket;
publicString ip;
publicint port;
publicInputStream is;
publicOutputStream os;
publicPrintWriter pw;
publicBufferedReader br;
publicstatic Context context;
privatestatic ThreadClient threadClient;
public static ThreadClient getThreadClient(Context c){
context = c;
if(threadClient == null){
try{
//创建Socket
Socket socket = newSocket("192.168.43.143", 8809);
threadClient = new ThreadClient(socket);
threadClient.start();
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return threadClient;
}
privateThreadClient(Socket socket) {
super();
this.socket = socket;
try {
this.ip= socket.getInetAddress().getHostAddress();
this.port= socket.getPort();
this.is= socket.getInputStream();
this.br= new BufferedReader(new InputStreamReader(is));
this.os= socket.getOutputStream();
this.pw= new PrintWriter(os);
} catch (Exception e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
//得到指定用户的信息
publicList<MessageInfo> getMessages(String key){
return messages.get(key);
}
@Override
publicvoid run() {
// TODO Auto-generated method stub
super.run();
while(true){
try{
String message = br.readLine();
if(message != null){
StringTokenizertoken = new StringTokenizer(message, "@");
Stringcmd = token.nextToken();
Stringip1 = token.nextToken();
int port1 = Integer.parseInt(token.nextToken());
//刷新用户的列表
if("refresh".equals(cmd)){
Log.i("i","ip:"+ip1+",port:"+port1);
//刷新列表界面
//发广播
boolean flag =this.ip.equals(ip1)&&this.port == port1;
Log.i("i","flag:"+flag);
if(!flag){//如果不是自己给自己发送的
userInfos.add(newUserInfo(ip1, port1));
Intentintent = new Intent();
intent.setAction("com.action.jky.MainActivity");
context.sendBroadcast(intent);
Log.i("i","已经发出广播");
//当有新的用户上线就创建一个新的消息集合
HashMap<String,List<MessageInfo>> messages = threadClient.messages;
messages.put(ip1+":"+port1,new ArrayList<MessageInfo>());
}
}elseif("text".equals(cmd)){
Log.i("i","得到服务器的消息:"+cmd);
//1 在MainActivity
//2 在ChatingActivity
String name =context.getClass().getName();
Log.i("i", "全类名"+name);
//消息的内容
String content = token.nextToken();
if("com.huaao.weixin.ui.MainActivity".equals(name)){
Intentintent = new Intent();
intent.setAction("com.huaao.weixin.ui.MainActivity");
intent.putExtra("ip",ip1);
intent.putExtra("port",port1);
intent.putExtra("content",content);
context.sendBroadcast(intent);
}elseif("com.huaao.weixin.ui.ChatingActivity".equals(name)){
Intentintent = new Intent();
intent.setAction("com.huaao.weixin.ui.ChatingActivity");
intent.putExtra("ip",ip1);
intent.putExtra("port",port1);
intent.putExtra("content",content);
context.sendBroadcast(intent);
}
}
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//发送消息 目标对象 消息内容
publicvoid sendMessage(String ip,int port,String message){
//找到目标对象:告诉服务消息要转发的ip 和 port
//text@ip@port@message
String msg ="text@"+ip+"@"+port+"@"+message;
pw.println(msg);
pw.flush();
}
}
Domain:
public class MessageInfo {
publicString content;
publicMessageInfo(String content) {
super();
this.content = content;
}
}
public class UserInfo {
publicString ip;
publicint port;
publicboolean isNew;//是否有新消息
publicUserInfo(String ip, int port) {
super();
this.ip = ip;
this.port = port;
}
}
Ui:
public class ChatingActivity extendsActivity {
privateTextView tv_title;
privateListView lv_message;
privateEditText et_message;
privateThreadClient threadClient;
privateString ip;
privateint port;
privateString key;
privateMyChatMessageAdapter adapter;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.chating);
tv_title = (TextView)findViewById(R.id.tv_title);
lv_message = (ListView)findViewById(R.id.lv_message);
et_message = (EditText)findViewById(R.id.et_message);
threadClient =ThreadClient.getThreadClient(this);
Intent intent = getIntent();
ip =intent.getStringExtra("ip");
port =intent.getIntExtra("port", 0);
key = ip+":"+port;
tv_title.setText(key);
List<MessageInfo> infos =threadClient.getMessages(key);
adapter = new MyChatMessageAdapter(this,infos);
lv_message.setAdapter(adapter);
IntentFilter filter = new IntentFilter();
filter.addAction("com.huaao.weixin.ui.ChatingActivity");
registerReceiver(new MyReceiver(),filter);
}
privateclass MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context,Intent intent) {
//TODO Auto-generated method stub
//得到消息
//把消息添加消息集合
//刷新界面
Stringip = intent.getStringExtra("ip");
intport = intent.getIntExtra("port", 0);
Stringcontent = intent.getStringExtra("content");
//把消息添加到消息集合
List<MessageInfo>messages = threadClient.getMessages(ip+":"+port);
messages.add(newMessageInfo(content));
adapter.notifyDataSetChanged();
}
}
publicvoid send(View v){
//得到消息
//发送消息
//把消息添加到消息集合
String message =et_message.getText().toString();
threadClient.sendMessage(ip, port,message);
List<MessageInfo> messages =threadClient.getMessages(key);
messages.add(new MessageInfo(message));
//刷新消息界面
adapter.notifyDataSetChanged();
}
}
public class MainActivity extends Activity{
private ListView lv_user;
privateMyUserAdapter adapter;
privateMyRefreshBroadCastReceiver receiver;
privateThreadClient threadClient;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
threadClient = ThreadClient.getThreadClient(this);
lv_user = (ListView) findViewById(R.id.lv_user);
List<UserInfo> userInfos = threadClient.userInfos;
adapter = new MyUserAdapter(userInfos, this);
lv_user.setAdapter(adapter);
//订阅广播
receiver = new MyRefreshBroadCastReceiver();
IntentFilter filter = new IntentFilter();
//用户上线
filter.addAction("com.action.jky.MainActivity");
//有新消息
filter.addAction("com.huaao.weixin.ui.MainActivity");
registerReceiver(receiver, filter);
//设置条目的点击事件
lv_user.setOnItemClickListener(new MyOnItemClickListener());
}
private class MyOnItemClickListener implements OnItemClickListener{
@Override
public voidonItemClick(AdapterView<?> parent, View view, int position,
long id) {
//TODO Auto-generated method stub
UserInfoinfo = (UserInfo) adapter.getItem(position);
Intentintent = new Intent(getApplicationContext(),ChatingActivity.class);
intent.putExtra("ip",info.ip);
intent.putExtra("port",info.port);
startActivity(intent);
//把新消息隐藏
view.findViewById(R.id.tv_isnew).setVisibility(View.INVISIBLE);
}
}
private class MyRefreshBroadCastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context,Intent intent) {
//TODO Auto-generated method stub
Stringaction = intent.getAction();
//用户上线
if("com.action.jky.MainActivity".equals(action)){
adapter.notifyDataSetChanged();
Log.i("i","得到通知刷新显示");
}elseif("com.huaao.weixin.ui.MainActivity".equals(action)){
Log.i("i","有广播到来。。可以出现有新消息");
//有新消息
String ip =intent.getStringExtra("ip");
int port =intent.getIntExtra("port", 0);
String content =intent.getStringExtra("content");
//把消息添加到消息集合
List<MessageInfo> messages =threadClient.getMessages(ip+":"+port);
messages.add(new MessageInfo(content));
//修改用户有新消息
List<UserInfo> userInfos =threadClient.userInfos;
for(UserInfo info:userInfos){
if(ip.equals(info.ip)&& port == info.port){
info.isNew = true;
break;
}
}
adapter.notifyDataSetChanged();
}
}
}
}