ym——Android从零开始(27)(山寨版微信-下)(新)

Android开发:山寨版微信实现(下)
本文继续介绍山寨版微信的实现,包括聊天功能的设计,消息的处理和存储,以及服务器消息转发的工作原理。内容涉及数据存储的选择、消息来源的区分、不同场景下的消息处理,并提供了一个简单的原理图。

转载请注明本文出自Cym的博客(http://blog.youkuaiyun.com/cym492224103),谢谢支持!


山寨版微信(下)

昨天 我们完成 上线列表刷新。

聊天:

消息:

用户发送:

只需要显示客户端的消息。

一个人可以和多个人聊天。

聊天的内容存放在哪里?数据库  内存  文件

你的数据是那个类来操作。

ThreadClient

HashMap<key,value>  value List<MessageInfo>

消息有两种来源:

自己发

别人发过来

唯一标示:ip+":"+port

服务器消息的转发工作

处理消息有两种情况:

没有聊天,我还在MainActivity

在聊天

原理图:

1.png

服务器:

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();
                     }
                     
                     
              }
           
    }
   
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值