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方法,则会直接报错.