Handler和runOnUIThread都是子线程操作UI线程界面元素的方案,之前一直以为runOnUIThread能做到的Handler也能做,但是今天发现了一个问题,只能用runOnUIThread,却不能用Handler解决。
手头上有个项目用到了模拟get请求,使用的是apache的httpClient,方法如下:
private static String getHtml(final String url) {
HttpEntity mEntity;
try {
HttpGet get = new HttpGet(url);
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
HttpResponse httpResponse = defaultHttpClient.execute(get);
mEntity = httpResponse.getEntity();
return EntityUtils.toString(mEntity);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
安卓中强制限定了,联网请求不能在UI线程中执行,所以调用这个方法时需要开子线程,以下就是使用子线程调用以上方法的方法:
public void connectNet(){
//我的项目中这里会先处理UI控件,所以请不要说什么这种应用场景不存在这类的话
new Thread(new Runnable() {
getHtml("http://www.baidu.com");
}).start();
}
以下是一个使用场景,在子线程下使用handler来调用connectNet():
//声明一个Handler,接收子线程中的信息,调用与消息对应的方法
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 100:
//如果信息是100,则调用connectNet()
connectNet();
break;
default:
break;
}
};
};
.........某个触发事件begin........
new Thread(new Runnable() {
.................
Message msg = mHandler.obtainMessage();
msg.what = 1000;
mHandler.sendMessage(msg);
.................
}).start();
........某个触发事件end.........
结果报错(超时):
org.apache.http.conn.HttpHostConnectException: Connection to http://www.baidu.com refused
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:188)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:369)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470)
at xxxxxxx//这是我自己项目的包信息,不方便透露
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.net.ConnectException: failed to connect to /www.baidu.com (port 9999): connect failed: ETIMEDOUT (Connection timed out)
at libcore.io.IoBridge.connect(IoBridge.java:124)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:456)
at java.net.Socket.connect(Socket.java:882)
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:124)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:149)
... 12 more
Caused by: android.system.ErrnoException: connect failed: ETIMEDOUT (Connection timed out)
at libcore.io.Posix.connect(Native Method)
at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:111)
at libcore.io.IoBridge.connectErrno(IoBridge.java:137)
at libcore.io.IoBridge.connect(IoBridge.java:122)
... 17 more
我以为方法有问题,就用按钮的点击事件来调用connectNet(),发现完全没有问题,工作正常。
分析:
1、按钮的点击事件是在UI线程中执行的,所以可以确定UI线程中可以调用connectNet(),即含有子线程的方法。
2、handler可以处理UI线程中的控件,理应属于UI线程(个人鄙见。。)。
3、猜测handler中不能执行含有子线程的操作的方法。
测试:
.........某个触发事件begin........
new Thread(new Runnable() {
.................
//用runOnUiThread代替handler
runOnUiThread(new Runnable() {
public void run() {
connectNet();
}
});
.................
}).start();
........某个触发事件end.........
结果:正常,效果与按钮的点击事件一样。