最近在学习网络加载库 async-http-client 有两个问题存在疑惑,恳请有研究过的 V 友指点一下:
SyncHttpClient 为何要在子线程中使用?
我已经知道 AsyncHttpClient 发异步请求是在sendRequest
方法中,通过以下代码新建AsyncHttpRequest
提交到线程池。
AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context);
threadPool.submit(request);
而 SyncHttpClient 是继承自 AsyncHttpClient ,重写了sendRequest
,但是在其方法中也调用了:
newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run();
我的疑惑:这里newAsyncHttpRequest
返回的AsyncHttpRequest
同样实现了Runnable
并调用了run()
方法,那么这不也是在子线程执行网络操作了。为什么我直接在 UI 线程调用
SyncHttpClient client = new SyncHttpClient();
client.get(MainActivity.this, "http://www.baidu.com", new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
}
});
为什么这里会报错:在主线程中执行了网络操作?
SyncHttpClient 是在如何在线程中进行阻塞的?
在一个子线程中进行两个请求,打印日志显示会等第一个请求结果返回才进行第二个请求,但是我查看其源码只找到一个responseHandler.setUseSynchronousMode(true);
貌似有关系,但是具体是怎么进行阻塞的还不明白?
上面是我的两个疑惑,希望请各位大神指点一下,谢谢!
1
linbiaye 2017-01-17 07:09:45 +08:00
1.为了保证用户体验,安卓规定不让在主线程中做网络 io ,主线程主要负责界面、交互。这个就是这么规定的,没有为什么。
2.感觉你现在不需要理解这个是怎么做到的,要理解这个怎么实现你需要知道 socket, tcp, http 是怎么回事,读取 socket(没有使用异步 io 下)就是阻塞的。 感觉你需要知道的是 sync 和 async 的区别? |
2
royliu OP @linbiaye 你好,感谢回复。
1.我知道 android 对主线程耗时操作不超过 5s 的规定,我只是想从源码的角度去理解时产生了疑惑。用 AsyncHttpClient 时是新建一个 AsyncHttpRequest 请求并 submit 到线程池里,所以相当于它本来就是运行在子线程中,在 UI 线程中也**不需要** new Thread ( new Runable{ AsyncHttpClient client = new AsyncHttpClient(); client.get(....); }) 但是使用 SyncHttpClient (继承 AsyncHttpClient )发起一个请求时,也是 new 了一个 AsyncHttpRequest 并直接调用其 run 方法,在我看来这两个貌似只有有没有加到线程池里面的区别,但是为什么这里需要 new Thread 并在里面进行请求? 2. 我确实是想知道 sync 和 async 的区别,因为在我看来它们是使用相同的 AsyncHttpRequest 和 responseHandler ,我想知道是哪里的代码使得处理 AsyncHttpClient 请求异步而处理 SyncHttpClient 请求时阻塞呢? |
3
naturs 2017-01-17 10:37:33 +08:00 1
AsyncHttpClient :
AsyncHttpRequest request = newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context); threadPool.submit(request); SyncHttpClient : newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run(); 一个用线程池 submit(),一个直接调用 run()方法,这就是区别。 |
4
linbiaye 2017-01-17 10:38:09 +08:00 1
1. 没明白你要表达啥。不管你是 sync 还是 async ,主线程都不让做 http 请求。你可以用线程池,也可以自己创建线程,反正别在我主线程做网络请求。
2.没读过,不知道具体实现 |
5
royliu OP |
6
iluhcm 2017-01-17 12:37:11 +08:00
第二点,一个子线程中进行两个请求,其实就相当于在一个非 UI 的 Looper 中 run 了两个方法,所以结果当然是先执行完第一个,结果回来以后才会去执行第二个。
另外,你上面说的把 newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run(); 当做 new Thread(newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).start()来理解是错误的。 直接调用 run()方法是在主线程执行的,调用 new Thread.start()方法是开启了一个新线程执行的,和调用 threadPool.submit(request)是一样的。 |
7
royliu OP @iluhcm 是的,我昨天提出这个问题,就是因为理解错误,把 newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run();理解成了 new Thread(newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).start()。一直在纠结明明这里新建了个线程,为什么在 UI 线程进行同步请求的时候还要 new Thread 。现在搞清楚了,感谢!
|
8
icris 2017-01-17 22:22:17 +08:00
是 https://github.com/AsyncHttpClient/async-http-client 这个吗?看起来不像 Android 用的东西,
>> It's built on top of Netty and currently requires JDK8. 还是推荐 Retrofit + RxJava 这一套,而且最好不要想着读它们的源码。 |