天天看點

Android NIO簡易聊天室

 <b>Android NIO</b><b>簡易聊天室</b>

<b>一、運作效果</b>

<b>1</b><b>)手機首界面</b>

<a href="http://blog.51cto.com/attachment/201207/113639423.png" target="_blank"></a>

<b>2</b><b>)手機伺服器</b>

<a href="http://blog.51cto.com/attachment/201207/113639802.png" target="_blank"></a>

<b>3</b><b>)手機用戶端</b>

<a href="http://blog.51cto.com/attachment/201207/113740216.png" target="_blank"></a>

<b>4</b><b>)電腦用戶端</b>

<a href="http://blog.51cto.com/attachment/201207/113822692.png" target="_blank"></a>

<b>5</b><b>)目前線上</b>

<a href="http://blog.51cto.com/attachment/201207/113740987.png" target="_blank"></a>

<b>二、</b><b>ChatActivity.java</b>

         聊天室界面了,主要都在這裡了。

<b></b>

public class ChatActivity extends TabActivity implements OnTabChangeListener, 

        Observer { 

    public static final int METHOD_CLIENT = 1; 

    public static final int METHOD_SERVER = 2; 

    private static final String BLANK = " "; 

    /** 啟動方式:用戶端、伺服器 */ 

    private int startMethod; 

    /** 線上用戶端資訊 */ 

    private HashMap&lt;InetSocketAddress, String&gt; onLineMap; 

    private ChatClient client; 

    private ChatServer server; 

    private LinearLayout msgLayout; 

    private ListView listView; 

    private EditText msgEdit; 

    private boolean isConnected = false; 

    private static final int UPDATE_SHOW_MESSAGE = 0; 

    private static final int UPDATE_TOAST_MESSAGE = 1; 

    private static final int UPDATE_LIST_DATA = 2; 

    private static final int MSG_COUNT = 20; 

    private Handler mHandler = new Handler(); 

    private class UpdateRunnable implements Runnable { 

       private String msg; 

       private int what; 

       public UpdateRunnable(String msg, int what) { 

           this.msg = msg; 

           this.what = what; 

       } 

       @Override 

       public void run() { 

           switch (what) { 

           case UPDATE_SHOW_MESSAGE: 

              TextView textView = new TextView(getBaseContext()); 

              textView.setText(msg); 

              if (msgLayout.getChildCount() &gt;= MSG_COUNT) { 

                  msgLayout.removeViewAt(0); 

              } 

              msgLayout.addView(textView); 

              break; 

           case UPDATE_TOAST_MESSAGE: 

              Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT) 

                     .show(); 

           case UPDATE_LIST_DATA: 

              if (null != onLineMap) { 

                  ArrayList&lt;String&gt; dataList = new ArrayList&lt;String&gt;(); 

                  Iterator&lt;Entry&lt;InetSocketAddress, String&gt;&gt; it = onLineMap 

                         .entrySet().iterator(); 

                  while (it.hasNext()) { 

                      Entry&lt;InetSocketAddress, String&gt; entry = it.next(); 

                     dataList.add(entry.getValue() 

                            + BLANK 

                            + Message.getInstance().toIpString( 

                                   entry.getKey())); 

                  } 

                  listView.setAdapter(new ArrayAdapter&lt;String&gt;( 

                         getBaseContext(), 

                         android.R.layout.simple_expandable_list_item_1, 

                         dataList)); 

           } 

    }; 

    private ProgressDialog progressDialog; 

    @Override 

    public void onCreate(Bundle savedInstanceState) { 

       super.onCreate(savedInstanceState); 

       createTabs(); // 建立标簽頁 

       startMethod = getIntent().getIntExtra(MainActivity.KEY_METHOD, 0); 

       msgLayout = (LinearLayout) findViewById(R.id.msgLayout); 

       listView = (ListView) findViewById(R.id.listView); 

       msgEdit = (EditText) findViewById(R.id.msgEdit); 

       final String address = getLocalIpAddress(); 

       if (null == address) { 

           toastMessage("請先開啟網絡"); 

       } else { 

           msgLayout.post(new Runnable() { 

              @Override 

              public void run() { 

                  start(startMethod, address); // 啟動服務 

           }); 

    } 

    protected void onStart() { 

       super.onStart(); 

    /** 建立标簽頁 */ 

    private void createTabs() { 

       TabHost tabHost = getTabHost(); 

       LayoutInflater.from(this).inflate(R.layout.chat, 

              tabHost.getTabContentView(), true); 

       tabHost.addTab(tabHost.newTabSpec("tab_chat").setIndicator("聊天室") 

              .setContent(R.id.chatTab)); 

       tabHost.addTab(tabHost.newTabSpec("tab_info").setIndicator("目前線上") 

              .setContent(R.id.infoTab)); 

       tabHost.setOnTabChangedListener(this); 

    /** 啟動服務 */ 

    private void start(int startMethod, String ipAddress) { 

       switch (startMethod) { 

       case METHOD_CLIENT: 

           /* 顯示圈形進度 */ 

           progressDialog = new ProgressDialog(this); 

           progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 

           progressDialog.setMessage("連接配接伺服器中..."); 

           progressDialog.setCancelable(false); 

           progressDialog.show(); 

           /* 連接配接伺服器 */ 

           String[] address = getIntent().getStringExtra( 

                  MainActivity.KEY_ADDRESS).split(":"); 

           client = new ChatClient(address[0], Integer.parseInt(address[1])); 

           client.addObserver(this); 

           client.start(); 

           setTitle(ipAddress); 

           break; 

       case METHOD_SERVER: 

           String port = getIntent().getStringExtra(MainActivity.KEY_PORT); 

           server = new ChatServer(Integer.parseInt(port)); 

           server.addObserver(this); 

           server.start(); 

           setTitle(ipAddress + ":" + port); 

    public void onTabChanged(String tabId) { 

    /** 發送消息 */ 

    public void send(View v) { 

       String msg = msgEdit.getText().toString().trim(); 

       if (msg.equals("")) { 

           msgEdit.setError("請輸入資訊"); 

           String newMsg = Message.MSG_4 + Message.SEPARATOR + msg; 

           if (null != client) { 

              client.send(newMsg); 

           if (null != server) { 

              server.send(newMsg); 

              showMessage("通知:" + msg); 

           msgEdit.setText(""); 

           hideSoftInput(); // 關閉軟鍵盤 

    public void update(Observable observable, Object data) { 

           updateClient(observable, data); 

           updateServer(observable, data); 

    /** 用戶端狀态更新 */ 

    private void updateClient(Observable observable, Object data) { 

       ChatClient client = (ChatClient) observable; 

       switch (client.getStatus()) { 

       case ChatClient.CLT_CONNECT: 

           // 發送登入消息 

           Message msg1 = Message.getInstance(); 

           msg1.setType(Message.MSG_1); 

           msg1.setMsg(getIntent().getStringExtra(MainActivity.KEY_NAME)); 

           client.send(msg1.toString()); 

           // 連接配接上後等伺服器傳回MSG_3再取消進度框等 

           isConnected = true; 

       case ChatClient.CLT_DISCONNECT: 

           isConnected = false; 

           if (null != progressDialog) { 

              progressDialog.dismiss(); 

           toastMessage("斷開伺服器連接配接"); 

           finish(); 

       case ChatClient.MSG_SEND: 

       case ChatClient.MSG_RECEIVE: 

           Message msg = Message.getInstance(); 

           msg.create((String) data); 

           handleClientMsg(msg); // 處理消息 

       case ChatClient.ERROR: 

           showMessage("error : " + ((Exception) data).getMessage()); 

    /** 用戶端資訊處理 */ 

    private void handleClientMsg(Message msg) { 

       int type = msg.getType(); 

       switch (type) { 

       case Message.MSG_2: 

           showMessage(msg.getMsg() + BLANK + msg.toIpString(msg.getFromIp()) 

                  + BLANK + "登入了"); 

           onLineMap.put(msg.getFromIp(), msg.getMsg()); 

           updateListData(); // 更新線上人員 

       case Message.MSG_3: 

           showMessage("連接配接上了伺服器"); 

           onLineMap = msg.getOnLineMap(); 

       case Message.MSG_4: 

           showMessage("通知:" + msg.getMsg()); 

       case Message.MSG_6: 

           showMessage(onLineMap.get(msg.getFromIp()) + BLANK + ":" + BLANK 

                  + msg.getMsg()); 

       case Message.MSG_8: 

           InetSocketAddress address = msg.getFromIp(); 

           showMessage(onLineMap.get(address) + BLANK 

                  + Message.getInstance().toIpString(address) + BLANK + "退出了"); 

           onLineMap.remove(address); 

    /** 伺服器狀态更新 */ 

    private void updateServer(Observable observable, Object data) { 

       ChatServer server = (ChatServer) observable; 

       switch (server.getStatus()) { 

       case ChatServer.SEV_ON: 

           showMessage("伺服器開啟了"); 

           onLineMap = new HashMap&lt;InetSocketAddress, String&gt;(); 

       case ChatServer.SEV_OFF: 

           toastMessage("伺服器關閉了"); 

           onLineMap = null; 

       case ChatServer.CLT_CONNECT: 

           // InetSocketAddress address = (InetSocketAddress) arg; 

       case ChatServer.CLT_DISCONNECT: 

           quit((InetSocketAddress) data); 

       case ChatServer.MSG_SEND: 

       case ChatServer.MSG_RECEIVE: 

           msg.create(server.getReceiveMessage()); 

           msg.setFromIp((InetSocketAddress) data); 

           handleServerMsg(msg); // 處理消息 

       case ChatServer.ERROR: 

    /** 用戶端退出 */ 

    private void quit(InetSocketAddress address) { 

       if (onLineMap.get(address) != null) { 

           msg.setType(Message.MSG_8); 

           msg.setFromIp(address); 

           server.send(msg.toString()); 

    /** 伺服器資訊處理 */ 

    private void handleServerMsg(Message msg) { 

        InetSocketAddress formIp = msg.getFromIp(); 

       case Message.MSG_1: 

           showMessage(msg.getMsg() + BLANK + msg.toIpString(formIp) + BLANK 

                  + "登入了"); 

           onLineMap.put(formIp, msg.getMsg()); 

           /* 通知所有用戶端新登入者資訊 */ 

           msg.setType(Message.MSG_2); 

           // msg.setFromIp(address); 

           /* 傳回登入用戶端所有線上用戶端資訊(會覆寫前一個發送給address的資訊) */ 

           msg.setType(Message.MSG_3); 

           msg.setOnLineMap(onLineMap); 

           server.send(msg.toString(), formIp); 

           msg.setType(Message.MSG_6); 

       case Message.MSG_7: 

           quit(formIp); 

    /** 展現資訊 */ 

    private void showMessage(String text) { 

       mHandler.post(new UpdateRunnable(text, UPDATE_SHOW_MESSAGE)); 

    /** 提示資訊 */ 

    private void toastMessage(String text) { 

       mHandler.post(new UpdateRunnable(text, UPDATE_TOAST_MESSAGE)); 

    /** 擷取目前IP位址 */ 

    private String getLocalIpAddress() { 

       try { 

           // 周遊網絡接口 

           for (Enumeration&lt;NetworkInterface&gt; en = NetworkInterface 

                  .getNetworkInterfaces(); en.hasMoreElements();) { 

              NetworkInterface intf = en.nextElement(); 

              // 周遊IP位址 

              for (Enumeration&lt;InetAddress&gt; enumIpAddr = intf 

                     .getInetAddresses(); enumIpAddr.hasMoreElements();) { 

                  InetAddress inetAddress = enumIpAddr.nextElement(); 

                  // 非回傳位址時傳回 

                  if (!inetAddress.isLoopbackAddress()) { 

                     return inetAddress.getHostAddress().toString(); 

       } catch (SocketException e) { 

           e.printStackTrace(); 

       return null; 

    /** 更新線上人員 */ 

    private void updateListData() { 

       mHandler.post(new UpdateRunnable(null, UPDATE_LIST_DATA)); 

    /** 關閉軟鍵盤 */ 

    private void hideSoftInput() { 

       InputMethodManager imm = (InputMethodManager) this 

              .getSystemService(Context.INPUT_METHOD_SERVICE); 

       imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); 

    protected void onDestroy() { 

       if (null != client) { 

           if (isConnected) { 

              client.send(Message.MSG_7 + ""); 

           client.close(); 

       if (null != server) { 

           server.close(); 

       super.onDestroy(); 

<b>三、其他</b>

         就這些了~

<a href="http://down.51cto.com/data/2360966" target="_blank">附件:http://down.51cto.com/data/2360966</a>

     本文轉自winorlose2000 51CTO部落格,原文連結:http://blog.51cto.com/vaero/921815,如需轉載請自行聯系原作者

繼續閱讀