android4.0以上网络访问为什么要开线程,已经Handler的使用

android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法

2013/9/30 11:29:36

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

 

 

网络连接不能放在主线程
android 4.0 以上    
网络连接不能放在主线程
4.0 以下 好像可以

android4.0以上网络访问为什么要开线程,已经Handler的使用_第1张图片




在Android4.0以后,会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时都会报错,这是因为Android在4.0以后为了防止应用的ANR(aplication Not Response)异常,即使这里表达不是很清晰,大家应该都明白吧,哈哈

就针对此问题有两种解决的方法:

1.可以再Activity的onCreate()方法中加入这样一段代码,如下:

if (Build.VERSION.SDK_INT >= 11) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads  ().detectDiskWrites().detectNetwork().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
}
后就可以在主线程中进行网络操作了

2.一般情况我们应该这样做

启动一条子线程进行你的网络请求。

当然,如果你的应用程序执行的网络请求数据量很小的话,可以使用第一种方案


你可能感兴趣的:(android)