Android NIO简易聊天室

 

         NIO通讯核心部分,参考前一篇《Java NIO 简易聊天室》。恩,这边就是Android上做个界面重新包装下。

 
一、运行效果
1 )手机首界面

Android NIO简易聊天室_第1张图片

 
2 )手机服务器

Android NIO简易聊天室_第2张图片

 
3 )手机客户端

Android NIO简易聊天室_第3张图片

 
4 )电脑客户端

Android NIO简易聊天室_第4张图片

 
5 )当前在线

Android NIO简易聊天室_第5张图片

 
二、 ChatActivity.java
         聊天室界面了,主要都在这里了。

   
   
   
   
  1. public class ChatActivity extends TabActivity implements OnTabChangeListener, 
  2.  
  3.         Observer { 
  4.   
  5.     public static final int METHOD_CLIENT = 1
  6.     public static final int METHOD_SERVER = 2
  7.   
  8.     private static final String BLANK = " "
  9.   
  10.     /** 启动方式:客户端、服务器 */ 
  11.     private int startMethod; 
  12.     /** 在线客户端信息 */ 
  13.     private HashMap onLineMap; 
  14.   
  15.     private ChatClient client; 
  16.     private ChatServer server; 
  17.   
  18.     private LinearLayout msgLayout; 
  19.     private ListView listView; 
  20.     private EditText msgEdit; 
  21.   
  22.     private boolean isConnected = false
  23.   
  24.     private static final int UPDATE_SHOW_MESSAGE = 0
  25.     private static final int UPDATE_TOAST_MESSAGE = 1
  26.     private static final int UPDATE_LIST_DATA = 2
  27.   
  28.     private static final int MSG_COUNT = 20
  29.     private Handler mHandler = new Handler(); 
  30.   
  31.     private class UpdateRunnable implements Runnable { 
  32.   
  33.        private String msg; 
  34.        private int what; 
  35.   
  36.        public UpdateRunnable(String msg, int what) { 
  37.            this.msg = msg; 
  38.            this.what = what; 
  39.        } 
  40.   
  41.        @Override 
  42.        public void run() { 
  43.            switch (what) { 
  44.            case UPDATE_SHOW_MESSAGE: 
  45.               TextView textView = new TextView(getBaseContext()); 
  46.               textView.setText(msg); 
  47.               if (msgLayout.getChildCount() >= MSG_COUNT) { 
  48.                   msgLayout.removeViewAt(0); 
  49.               } 
  50.               msgLayout.addView(textView); 
  51.               break
  52.            case UPDATE_TOAST_MESSAGE: 
  53.               Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT) 
  54.                      .show(); 
  55.               break
  56.            case UPDATE_LIST_DATA: 
  57.               if (null != onLineMap) { 
  58.                   ArrayList dataList = new ArrayList(); 
  59.  
  60.                   Iterator> it = onLineMap 
  61.  
  62.                          .entrySet().iterator(); 
  63.                   while (it.hasNext()) { 
  64.                       Entry entry = it.next(); 
  65.  
  66.                      dataList.add(entry.getValue() 
  67.                             + BLANK 
  68.                             + Message.getInstance().toIpString( 
  69.                                    entry.getKey())); 
  70.                   } 
  71.                   listView.setAdapter(new ArrayAdapter
  72.                          getBaseContext(), 
  73.                          android.R.layout.simple_expandable_list_item_1, 
  74.                          dataList)); 
  75.               } 
  76.               break
  77.            } 
  78.        } 
  79.   
  80.     }; 
  81.   
  82.     private ProgressDialog progressDialog; 
  83.   
  84.     @Override 
  85.     public void onCreate(Bundle savedInstanceState) { 
  86.        super.onCreate(savedInstanceState); 
  87.   
  88.        createTabs(); // 创建标签页 
  89.        startMethod = getIntent().getIntExtra(MainActivity.KEY_METHOD, 0); 
  90.   
  91.        msgLayout = (LinearLayout) findViewById(R.id.msgLayout); 
  92.        listView = (ListView) findViewById(R.id.listView); 
  93.        msgEdit = (EditText) findViewById(R.id.msgEdit); 
  94.   
  95.        final String address = getLocalIpAddress(); 
  96.        if (null == address) { 
  97.            toastMessage("请先开启网络"); 
  98.        } else { 
  99.            msgLayout.post(new Runnable() { 
  100.               @Override 
  101.               public void run() { 
  102.                   start(startMethod, address); // 启动服务 
  103.               } 
  104.            }); 
  105.        } 
  106.     } 
  107.   
  108.     @Override 
  109.     protected void onStart() { 
  110.        super.onStart(); 
  111.     } 
  112.   
  113.     /** 创建标签页 */ 
  114.     private void createTabs() { 
  115.        TabHost tabHost = getTabHost(); 
  116.        LayoutInflater.from(this).inflate(R.layout.chat, 
  117.               tabHost.getTabContentView(), true); 
  118.        tabHost.addTab(tabHost.newTabSpec("tab_chat").setIndicator("聊天室"
  119.               .setContent(R.id.chatTab)); 
  120.        tabHost.addTab(tabHost.newTabSpec("tab_info").setIndicator("当前在线"
  121.               .setContent(R.id.infoTab)); 
  122.        tabHost.setOnTabChangedListener(this); 
  123.     } 
  124.   
  125.     /** 启动服务 */ 
  126.     private void start(int startMethod, String ipAddress) { 
  127.        switch (startMethod) { 
  128.        case METHOD_CLIENT: 
  129.            /* 显示圈形进度 */ 
  130.            progressDialog = new ProgressDialog(this); 
  131.            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
  132.            progressDialog.setMessage("连接服务器中..."); 
  133.            progressDialog.setCancelable(false); 
  134.            progressDialog.show(); 
  135.            /* 连接服务器 */ 
  136.            String[] address = getIntent().getStringExtra( 
  137.                   MainActivity.KEY_ADDRESS).split(":"); 
  138.            client = new ChatClient(address[0], Integer.parseInt(address[1])); 
  139.            client.addObserver(this); 
  140.            client.start(); 
  141.            setTitle(ipAddress); 
  142.            break
  143.        case METHOD_SERVER: 
  144.            String port = getIntent().getStringExtra(MainActivity.KEY_PORT); 
  145.            server = new ChatServer(Integer.parseInt(port)); 
  146.            server.addObserver(this); 
  147.            server.start(); 
  148.            setTitle(ipAddress + ":" + port); 
  149.            break
  150.        } 
  151.     } 
  152.   
  153.     @Override 
  154.     public void onTabChanged(String tabId) { 
  155.     } 
  156.   
  157.     /** 发送消息 */ 
  158.     public void send(View v) { 
  159.        String msg = msgEdit.getText().toString().trim(); 
  160.        if (msg.equals("")) { 
  161.            msgEdit.setError("请输入信息"); 
  162.        } else { 
  163.            String newMsg = Message.MSG_4 + Message.SEPARATOR + msg; 
  164.            if (null != client) { 
  165.               client.send(newMsg); 
  166.            } 
  167.            if (null != server) { 
  168.               server.send(newMsg); 
  169.               showMessage("通知:" + msg); 
  170.            } 
  171.            msgEdit.setText(""); 
  172.            hideSoftInput(); // 关闭软键盘 
  173.        } 
  174.     } 
  175.   
  176.     @Override 
  177.     public void update(Observable observable, Object data) { 
  178.        switch (startMethod) { 
  179.        case METHOD_CLIENT: 
  180.            updateClient(observable, data); 
  181.            break
  182.        case METHOD_SERVER: 
  183.            updateServer(observable, data); 
  184.            break
  185.        } 
  186.     } 
  187.   
  188.     /** 客户端状态更新 */ 
  189.     private void updateClient(Observable observable, Object data) { 
  190.        ChatClient client = (ChatClient) observable; 
  191.        switch (client.getStatus()) { 
  192.        case ChatClient.CLT_CONNECT: 
  193.            // 发送登录消息 
  194.            Message msg1 = Message.getInstance(); 
  195.            msg1.setType(Message.MSG_1); 
  196.            msg1.setMsg(getIntent().getStringExtra(MainActivity.KEY_NAME)); 
  197.            client.send(msg1.toString()); 
  198.            // 连接上后等服务器返回MSG_3再取消进度框等 
  199.            isConnected = true
  200.            break
  201.        case ChatClient.CLT_DISCONNECT: 
  202.            isConnected = false
  203.            if (null != progressDialog) { 
  204.               progressDialog.dismiss(); 
  205.            } 
  206.            toastMessage("断开服务器连接"); 
  207.            finish(); 
  208.            break
  209.        case ChatClient.MSG_SEND: 
  210.            break
  211.        case ChatClient.MSG_RECEIVE: 
  212.            Message msg = Message.getInstance(); 
  213.            msg.create((String) data); 
  214.            handleClientMsg(msg); // 处理消息 
  215.            break
  216.        case ChatClient.ERROR: 
  217.            showMessage("error : " + ((Exception) data).getMessage()); 
  218.  
  219.            break
  220.        } 
  221.     } 
  222.   
  223.     /** 客户端信息处理 */ 
  224.     private void handleClientMsg(Message msg) { 
  225.        int type = msg.getType(); 
  226.        switch (type) { 
  227.        case Message.MSG_2: 
  228.            showMessage(msg.getMsg() + BLANK + msg.toIpString(msg.getFromIp()) 
  229.                   + BLANK + "登录了"); 
  230.            onLineMap.put(msg.getFromIp(), msg.getMsg()); 
  231.            updateListData(); // 更新在线人员 
  232.            break
  233.        case Message.MSG_3: 
  234.            showMessage("连接上了服务器"); 
  235.            onLineMap = msg.getOnLineMap(); 
  236.            updateListData(); // 更新在线人员 
  237.            if (null != progressDialog) { 
  238.               progressDialog.dismiss(); 
  239.            } 
  240.            break
  241.        case Message.MSG_4: 
  242.            showMessage("通知:" + msg.getMsg()); 
  243.            break
  244.        case Message.MSG_6: 
  245.            showMessage(onLineMap.get(msg.getFromIp()) + BLANK + ":" + BLANK 
  246.                   + msg.getMsg()); 
  247.            break
  248.        case Message.MSG_8: 
  249.            InetSocketAddress address = msg.getFromIp(); 
  250.            showMessage(onLineMap.get(address) + BLANK 
  251.                   + Message.getInstance().toIpString(address) + BLANK + "退出了"); 
  252.  
  253.            onLineMap.remove(address); 
  254.            updateListData(); // 更新在线人员 
  255.            break
  256.        } 
  257.     } 
  258.   
  259.     /** 服务器状态更新 */ 
  260.     private void updateServer(Observable observable, Object data) { 
  261.        ChatServer server = (ChatServer) observable; 
  262.        switch (server.getStatus()) { 
  263.        case ChatServer.SEV_ON: 
  264.            showMessage("服务器开启了"); 
  265.            onLineMap = new HashMap(); 
  266.            break
  267.        case ChatServer.SEV_OFF: 
  268.            toastMessage("服务器关闭了"); 
  269.            onLineMap = null
  270.            finish(); 
  271.            break
  272.        case ChatServer.CLT_CONNECT: 
  273.            // InetSocketAddress address = (InetSocketAddress) arg; 
  274.  
  275.            break
  276.        case ChatServer.CLT_DISCONNECT: 
  277.            quit((InetSocketAddress) data); 
  278.            break
  279.        case ChatServer.MSG_SEND: 
  280.            break
  281.        case ChatServer.MSG_RECEIVE: 
  282.            Message msg = Message.getInstance(); 
  283.            msg.create(server.getReceiveMessage()); 
  284.            msg.setFromIp((InetSocketAddress) data); 
  285.            handleServerMsg(msg); // 处理消息 
  286.            break
  287.        case ChatServer.ERROR: 
  288.            showMessage("error : " + ((Exception) data).getMessage()); 
  289.  
  290.            break
  291.        } 
  292.     } 
  293.   
  294.     /** 客户端退出 */ 
  295.     private void quit(InetSocketAddress address) { 
  296.        if (onLineMap.get(address) != null) { 
  297.            showMessage(onLineMap.get(address) + BLANK 
  298.                   + Message.getInstance().toIpString(address) + BLANK + "退出了"); 
  299.  
  300.            onLineMap.remove(address); 
  301.            Message msg = Message.getInstance(); 
  302.            msg.setType(Message.MSG_8); 
  303.            msg.setFromIp(address); 
  304.            server.send(msg.toString()); 
  305.            updateListData(); // 更新在线人员 
  306.        } 
  307.     } 
  308.   
  309.     /** 服务器信息处理 */ 
  310.     private void handleServerMsg(Message msg) { 
  311.        int type = msg.getType(); 
  312.         InetSocketAddress formIp = msg.getFromIp(); 
  313.  
  314.        switch (type) { 
  315.        case Message.MSG_1: 
  316.            showMessage(msg.getMsg() + BLANK + msg.toIpString(formIp) + BLANK 
  317.                   + "登录了"); 
  318.            onLineMap.put(formIp, msg.getMsg()); 
  319.            updateListData(); // 更新在线人员 
  320.            /* 通知所有客户端新登录者信息 */ 
  321.            msg.setType(Message.MSG_2); 
  322.            // msg.setFromIp(address); 
  323.  
  324.            server.send(msg.toString()); 
  325.            /* 返回登录客户端所有在线客户端信息(会覆盖前一个发送给address的信息) */ 
  326.            msg.setType(Message.MSG_3); 
  327.            msg.setOnLineMap(onLineMap); 
  328.            server.send(msg.toString(), formIp); 
  329.            break
  330.        case Message.MSG_4: 
  331.            showMessage(onLineMap.get(msg.getFromIp()) + BLANK + ":" + BLANK 
  332.                   + msg.getMsg()); 
  333.            msg.setType(Message.MSG_6); 
  334.            server.send(msg.toString()); 
  335.            break
  336.        case Message.MSG_7: 
  337.            quit(formIp); 
  338.            break
  339.        } 
  340.     } 
  341.   
  342.     /** 展现信息 */ 
  343.     private void showMessage(String text) { 
  344.        mHandler.post(new UpdateRunnable(text, UPDATE_SHOW_MESSAGE)); 
  345.     } 
  346.   
  347.     /** 提示信息 */ 
  348.     private void toastMessage(String text) { 
  349.        mHandler.post(new UpdateRunnable(text, UPDATE_TOAST_MESSAGE)); 
  350.     } 
  351.   
  352.     /** 获取当前IP地址 */ 
  353.     private String getLocalIpAddress() { 
  354.        try { 
  355.            // 遍历网络接口 
  356.            for (Enumeration en = NetworkInterface 
  357.  
  358.                   .getNetworkInterfaces(); en.hasMoreElements();) { 
  359.  
  360.               NetworkInterface intf = en.nextElement(); 
  361.               // 遍历IP地址 
  362.               for (Enumeration enumIpAddr = intf 
  363.                      .getInetAddresses(); enumIpAddr.hasMoreElements();) { 
  364.  
  365.                   InetAddress inetAddress = enumIpAddr.nextElement(); 
  366.                   // 非回传地址时返回 
  367.                   if (!inetAddress.isLoopbackAddress()) { 
  368.                      return inetAddress.getHostAddress().toString(); 
  369.                   } 
  370.               } 
  371.            } 
  372.        } catch (SocketException e) { 
  373.            e.printStackTrace(); 
  374.        } 
  375.        return null
  376.     } 
  377.   
  378.     /** 更新在线人员 */ 
  379.     private void updateListData() { 
  380.        mHandler.post(new UpdateRunnable(null, UPDATE_LIST_DATA)); 
  381.     } 
  382.   
  383.     /** 关闭软键盘 */ 
  384.     private void hideSoftInput() { 
  385.        InputMethodManager imm = (InputMethodManager) this 
  386.               .getSystemService(Context.INPUT_METHOD_SERVICE); 
  387.        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); 
  388.  
  389.     } 
  390.   
  391.     @Override 
  392.     protected void onDestroy() { 
  393.        if (null != client) { 
  394.            if (isConnected) { 
  395.               client.send(Message.MSG_7 + ""); 
  396.            } 
  397.            client.close(); 
  398.        } 
  399.        if (null != server) { 
  400.            server.close(); 
  401.        } 
  402.        super.onDestroy(); 
  403.     } 
  404.   
 
三、其他
         就这些了~