<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<InetSocketAddress, String> 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() >= 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<String> dataList = new ArrayList<String>();
Iterator<Entry<InetSocketAddress, String>> it = onLineMap
.entrySet().iterator();
while (it.hasNext()) {
Entry<InetSocketAddress, String> entry = it.next();
dataList.add(entry.getValue()
+ BLANK
+ Message.getInstance().toIpString(
entry.getKey()));
}
listView.setAdapter(new ArrayAdapter<String>(
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<InetSocketAddress, String>();
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<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
// 周遊IP位址
for (Enumeration<InetAddress> 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,如需轉載請自行聯系原作者