Android 聊天室(一)

摘要:
为了提高自己在Android开发方面的能力,这位博主决定编写一款类似QQ和微信的聊天软件。作为安卓开发者,小白没有足够的实力在这款应用的开发上取得巨大突破。因此,这位博主提到了疯狂的Android讲义中的“Android网络应用程序”部分。在第一阶段,多人聊天室主要通过套接字和多线程实现。接下来,博主将从服务器端和Android客户端详细介绍实现过程:服务器的主要功能是与客户端建立套接字连接;转发客户端发送的消息。

         为了提高自己在Android开发上的能力,博主决定写一个类似于QQ、微信的聊天软件。不过,简单的想想之后发现,要实现这样的一个聊天软件,需要学习和掌握的东西还很多。作为一个Android开发的小白,也没有足够的实力能很快对这个APP的开发有很大的突破。

         于是,博主参考《疯狂Android讲义》中关于“Android网络应用”部分。首先从简单的聊天功能进行实现。第一阶段,主要实现的是一个多人聊天室,通过socket以及多线程进行实现。

具体过程为:

chatroom

  1. Client A、Client B、Client C 分别与Server建立socket连接。
  2. 每建立一个连接Server将把这个socket存储在一个socketList的列表里。
  3. 每当其中一个客户端“说话”时(以Client A 为例),Server收到Client A 发出的消息将会遍历整个socketList,将这条信息广播给当前所有已经建立了socket连接的Client

下面,博主将从服务器端以及Android客户端,对这个实现过程进行详细的介绍:

  • Server

主要实现功能:与客户端建立socket连接;对Client发送的消息进行转发。

MyServer.java

public class MyServer {

       static BufferedReader br;
       static int index = 0;
       public static ArrayList<Socket> socketList = new ArrayList<>();
       public static void main(String[] args) throws IOException {
            ServerSocket ss =new ServerSocket(30000); //开启30000号端口
             while(true ){
                  Socket s = ss.accept();
                         socketList.add(s);
                         new Thread(new ServerThread(s)).start();        
            } //持续接收来自Client的socket连接,并将socket加入列表
      }
}
ServerTread.java
public class ServerThread implements Runnable {
      Socket s = null;
      BufferedReader br = null;
      
       public ServerThread(Socket s) throws IOException{
             this.s = s;
             br = new BufferedReader(new InputStreamReader(s.getInputStream()
                                                                    , "utf-8" ));
      }
      
       @Override
       public void run() {
             try {
                  String content = null;
                   while((content = readFromClient()) != null){
                         for(Socket s : MyServer.socketList){
                              OutputStream os = s.getOutputStream();
                              os.write((content + "
").getBytes("utf-8" ));
                        }                 
                  } //遍历整个socketList,将信息写入输出流进行广播
            } catch (Exception e) {
                  e.printStackTrace();
            }
      }

       private String readFromClient() {
             try {
                   return br .readLine();
            } catch (Exception e) {
                  MyServer. socketList.remove(s ); //读取信息失败则移除socket
            }
             return null ;
      }

}
  • Client

主要实现功能:与服务器建立socket连接;实现消息的发送与接受。

Chat.java

public class Chat extends Activity {

      TextView tv_name;
      EditText et_input;
      Button bt_send;   
      ClientThread clientThread;
      
      
       private ListView listview ;
       private List<ChatMessage> mData ;
       private ChatMessageAdapter mAdapter ;
      
      
       private static final String tag = "Chat";
      
       private Handler handler = new Handler(){

             @Override
             public void handleMessage(android.os.Message msg) {
                   if(msg.what == 0x123){
                        ChatMessage receiveMsg =  (ChatMessage) msg. obj;
                         mData.add(receiveMsg);
                         mAdapter.notifyDataSetChanged();
                         listview.setSelection(mData .size() - 1);
                  }
            }
            
      };
      
       @Override
       protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
            requestWindowFeature(Window. FEATURE_NO_TITLE);
            setContentView(R.layout. chat);
      
            initView(); //初始化view
            
            initData(); //初始化数据
            
             clientThread = new ClientThread(handler);
             new Thread(clientThread ).start(); //启动新线程发送信息
            
             bt_send.setOnClickListener(new OnClickListener() {
                  
                   @Override
                   public void onClick(View v) {
                         final String inputMsg = et_input.getText().toString();
                        Log. v(tag, "inputMsg: " + inputMsg);
                         if(TextUtils.isEmpty(inputMsg)){
                              Toast. makeText(Chat.this, "发送消息不能为空!" , Toast. 
                                                                                      LENGTH_SHORT).show();
                        }
                         try {
                              ChatMessage cm = new ChatMessage();
                              cm.setDate( new Date());
                              cm.setMsg(inputMsg);
                              cm.setType(Type. OUTCOMING);
                              cm.setName( "paul");
                               mData.add(cm);
                               mAdapter.notifyDataSetChanged();
                               listview.setSelection(mData .size() - 1);
                              
                              Message msg = new Message();
                              msg. what = 0x345;
                              msg. obj = inputMsg;
                               et_input.setText("" );
                               clientThread.revHandler .sendMessage(msg); //发送信息

                              
                        } catch (Exception e) {
                              e.printStackTrace();
                        }
                                          
                  }           
            });
      }

       private void initData() {
             mData = new ArrayList<ChatMessage>();
            String data = et_input.getText().toString();
            
             mAdapter = new ChatMessageAdapter(Chat.this, mData);
             listview.setAdapter(mAdapter );
            
      }

       private void initView() {
             tv_name = (TextView) findViewById(R.id.tv_name);
             et_input = (EditText) findViewById(R.id.et_input);
             bt_send = (Button) findViewById(R.id.bt_send);
             listview = (ListView) findViewById(R.id.id_listview);
            
      }

ClientTread.java

public class ClientThread implements Runnable {

       private Socket s ;
       private Handler handler ;
       public Handler revHandler ;
      
      BufferedReader br = null;
      OutputStream os = null;
      
       public ClientThread(Handler handler) {
             this.handler = handler;
      }

       @Override
       public void run() {
             try {
                   s = new Socket("10.105.36.51" , 30000); //通过ip地址和端口号连接服务器
                   br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                   os = s.getOutputStream();
                  
                   new Thread(){

                         @Override
                         public void run() {
                              String content = null;
                               try {
                                     while((content = br .readLine()) != null){
                                          ChatMessage cm =new ChatMessage();
                                          cm.setDate( new Date());
                                          cm.setMsg(content);
                                          cm.setType(Type. INCOMING);
                                          cm.setName( "paul");
                                          
                                          Message msg = new Message();
                                          msg. what = 0x123;
                                          msg. obj = cm;
                                           handler.sendMessage(msg);
                                    }
                              } catch (IOException e) {
                                    e.printStackTrace();
                              }
                        }
                        
                  }.start();
                  
                  Looper. prepare();
                  
                   revHandler = new Handler(){

                         @Override
                         public void handleMessage(Message msg) {
                               if(msg.what == 0x345){
                                     try {
                                           os.write((msg. obj.toString() + "
").getBytes("utf-8" )); //将信息写入输出流发送给服务器
                                    } catch (IOException e) {
                                          e.printStackTrace();
                                    }
                              }
                        }
                        
                  };
                  Looper. loop();
            } catch (SocketTimeoutException e) {
                  System. out.println("网络连接超时!" );
            } catch (Exception e) {
                  e.printStackTrace();
            }

      }

}

免责声明:文章转载自《Android 聊天室(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇c#使用Confluent.Kafka实现生产者发送消息至kafka(远程连接kafka发送消息超时的解决 Local:Message timed out)微信开发笔记:获取用户openid,以及用户头像昵称等信息下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

android网络交互之DNS优化知识整理

android网络交互之DNS优化知识整理 之前的工作中,经常会遇到DNS解析出问题导致网络交互的操作无法正常进行。 UnknownHostException 在很多的移动开发过程中,与服务端的交互的url通常是包含域名的。而在实际的网络交互的过程中,第一步就需要对域名进行dns解析。 复杂的网络环境里面,dns解析会耗费很长的时间、甚至是解析失败。这是经...

用js判断页面刷新或关闭的方法

onbeforeunload与onunload事件 Onunload,onbeforeunload都是在刷新或关闭时调用,可以在<script>脚本中通过window.onunload来指定或者在<body>里指定。区别在于onbeforeunload在onunload之前执行,它还可以阻止onunload的执行。 Onbefor...

Android Webview的测试

1.查看当前的所有窗口:         Set contexts= driver.getContextHandles();         System.out.println(contexts); 打印出当前所有的窗口 Set<String> contextNames = driver.getContextHandles();      ...

Handler处理长时间事件

当我们在处理一些比较长时间的事件时候,比如读取网络或者数据库的数据时候,就要用到Handler,有时候为了不影响用户操作应用的流畅还要开多一个线程来区别UI线程,在新的线程里面处理长时间的操作。开发的时候遇到数据处理都可以这样用handler,灵活修改一下就可以做各种效果了。 第一步:ProgressDialog弹出旋转框来提示长时间操作。 第二步:开多一...

Android开发 BottomNavigationView学习

前言  注意这个里介绍的是AndroidX的com.google.android.material.bottomnavigation.BottomNavigationView xml布局中 <com.google.android.material.bottomnavigation.BottomNavigationView and...

php SWFUpload多文件上传

什么是SWFUpload SWFUpload是一个网站前端文件上传组件。SWFUpload通过flash+JavaScript,实现在不刷新网页的条件下,多个文件批量上传(实际上是逐个上传)、以及显示上传进度。 SWFUpload基本原理 1、传统的html表单文件上传 传统的文件上传是使用下面这种Form的: 1 <formid="file...