1.功能分析:
服務器端線程類不斷讀取客戶端數據,讀到客戶端數據後,將該數據向所有客戶端發送一次,
而客戶端包含兩條線程:
一條將用戶輸入數據寫入Socket對應的輸出流中;
另一條負責讀取Socket對應輸入流中的數據(即從服務器發送過來的數據)。
2.客戶端實現細節分析:
在客戶端子線程中分別定義向UI線程發送消息的Handler對象(hanler) 和 接收UI線程的消息的Handler對象(recvHandler)。
public class ClientThread implements Runnable{Handler handler = null;//send msg to UI
Handler recvHandler = null;//recv msg from UI
public ClientThread(Handler handler){
this.handler = handler;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
new Thread(){
@Override
public void run(){
//child thread : read data from the server
}
}
}.start();
Looper.prepare();
recvHandler = new Handler(){
@Override
public void handleMessage(Message msg){
//send msg to the server
if(msg.what == MultiThreadClient.SEND_MSG){
try {
os.write((msg.obj.toString()+"\r\n").getBytes("utf-8"));
}
};
Looper.loop();
}
}
3.Review looper
àHandler的主要作用是發送消息和處理消息,被Handler發送的消息必須被送到指定的MessageQueue,而MessageQueue又是由Looper負責管理的。即希望Handler正常工作,必須在當前線程中有一個Looper對象。
所以在線程中使用Handler的步驟如下:
4.tips
(1) UTF-8 編碼問題
(2)
pro in server:
read_msg = br.readLine();//alwaysblock 2014 4.3 17:17 ???
solution:
in client
os.write((msg.obj.toString()+"\r\n").getBytes("utf-8"));
(3)
讀取的內容---追加---顯示在文本框中,避免沖掉前面的消息
show.append("\n" +msg.obj.toString());
(4)
0001.android開發中有editetext,當輸入時輸入法會把底部的導航欄頂上去。如何解決?
AndroidManifest.xml文件中界面對應的<activity>里加入
android:windowSoftInputMode="adjustPan" 鍵盤就會覆蓋屏幕
android:windowSoftInputMode="stateVisible|adjustResize" 屏幕整體上移
"adjustResize"
該 Activity主窗口總是被調整屏幕的大小以便留出軟鍵盤的空間
6.Other Pro:
(1) why alternate the following two block ,the program cannotrun correctly ?
public void run() {
Block1:
new Thread(){
read data from server
}
Block2:
Looper.prepare();
Send message to server
Looper.loop();
}
(1).MultiThread界面優化 自適應長度 滾動條 將消息頂上去
(2.)其它一些不正確的斷開連接 拋出的異常等問題
java.net.SocketException: Software causedconnection abort: socket write error
atjava.net.SocketOutputStream.socketWrite0(Native Method)
atjava.net.SocketOutputStream.socketWrite(Unknown Source)
atjava.net.SocketOutputStream.write(Unknown Source)
atServerThread.run(ServerThread.java:49)
atjava.lang.Thread.run(Unknown Source)
(3)Analysis looper:
子線程中的Handler對象必須是在run方法中創建,纔是真正屬於子線程的.如果在子線程的onCreate方法中創建,則該Handler對象關聯於主線程.
Android對於在子線程中創建Handler對象有明確的約束,即:如果用戶試圖在子線程(run方法)中創建handler對象,而未事先調用Looper.prepare方法,則會直接報錯.