剛剛上手android,在寫一個利用Socket與服務器端進行通信的Demo時候報了一個android.os.NetworkOnMainThreadException的異常:
服務器端:
public class SimpleServer {
public static void main(String[] args){
try {
ServerSocket ss=new ServerSocket(40000);
System.out.println("等待連接......");
while(true){
Socket s=ss.accept();
OutputStream os=s.getOutputStream();
os.write("hello".getBytes("utf-8"));
os.close();
s.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
求助度娘後發現是SDK的版本問題,android4.0中訪問網絡不能在主程序中進行,行吧,那就老老實實的重新開啓一個線程:
new Thread(){
public void run(){
try {
Socket s=new Socket("172.22.16.26", 40000);
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=br.readLine();
show.setText("服務器說:"+line);
br.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
結果又報了異常:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
相信各位已經看出了在下犯了一個很低級的錯誤:在新啓的線程中操作UI,UI線程是非線程安全的,Android平臺不允許Activity新啓動的線程訪問該Activity裏的界面組件,這時就要藉助Handler的消息傳遞機制了:
new Thread(){
public void run(){
try {
Socket s=new Socket("172.18.6.26",40000);
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=br.readLine();
//System.out.println("服務器說:"+line);
Message msg=new Message();
msg.what=0x123;
msg.obj=line;
myhandler.sendMessage(msg);
br.close();
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
然後重寫handlerMessage方法獲取消息:
final Handler myhandler=new Handler(){
public void handleMessage(Message msg){
if(msg.what==0x123){
System.out.println("--------------->"+msg.obj);
show2.setText((String)msg.obj);
}
}
};
當新線程發送消息時,該方法自動被調用,handlerMessage(Message msg)方法依舊位於主線程中,所以可以動態的修改UI組件。