刚刚上手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组件。