关于 async-http-client 中 SyncHttpClient 与 AsyncHttpClient 的问题求指点 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
royliu

关于 async-http-client 中 SyncHttpClient 与 AsyncHttpClient 的问题求指点

  •  
  •   royliu 2017 年 1 月 16 日 15593 次点击
    这是一个创建于 3385 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在学习网络加载库 async-http-client 有两个问题存在疑惑,恳请有研究过的 V 友指点一下:

    1. 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) { } }); 

      为什么这里会报错:在主线程中执行了网络操作?

    2. SyncHttpClient 是在如何在线程中进行阻塞的?

      在一个子线程中进行两个请求,打印日志显示会等第一个请求结果返回才进行第二个请求,但是我查看其源码只找到一个responseHandler.setUseSynchronousMode(true);貌似有关系,但是具体是怎么进行阻塞的还不明白?

    上面是我的两个疑,希望请各位大神指点一下,谢谢!

    9 条回复    2017-01-17 22:57:11 +08:00
    linbiaye
        1
    linbiaye  
       2017 年 1 月 17 日
    1.为了保证用户体验,安卓规定不让在主线程中做网络 io ,主线程主要负责界面、交互。这个就是这么规定的,没有为什么。
    2.感觉你现在不需要理解这个是怎么做到的,要理解这个怎么实现你需要知道 socket, tcp, http 是怎么回事,读取 socket(没有使用异步 io 下)就是阻塞的。 感觉你需要知道的是 sync 和 async 的区别?
    royliu
        2
    royliu  
    OP
       2017 年 1 月 17 日
    @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 请求时阻塞呢?
    naturs
        3
    naturs  
       2017 年 1 月 17 日   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()方法,这就是区别。
    linbiaye
        4
    linbiaye  
       2017 年 1 月 17 日   1
    1. 没明白你要表达啥。不管你是 sync 还是 async ,主线程都不让做 http 请求。你可以用线程池,也可以自己创建线程,反正别在我主线程做网络请求。
    2.没读过,不知道具体实现
    royliu
        5
    royliu  
    OP
       2017 年 1 月 17 日
    @linbiaye @naturs 被自己绕进去了,把 newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run(); 当做 new Thread ( newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context)).start()来理解了。感谢两位!
    iluhcm
        6
    iluhcm  
       2017 年 1 月 17 日
    第二点,一个子线程中进行两个请求,其实就相当于在一个非 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)是一样的。
    royliu
        7
    royliu  
    OP
       2017 年 1 月 17 日
    @iluhcm 是的,我昨天提出这个问题,就是因为理解错误,把 newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).run();理解成了 new Thread(newAsyncHttpRequest(client, httpContext, uriRequest, contentType, responseHandler, context).start()。一直在纠结明明这里新建了个线程,为什么在 UI 线程进行同步请求的时候还要 new Thread 。现在搞清楚了,感谢!
    icris
        8
    icris  
       2017 年 1 月 17 日
    https://github.com/AsyncHttpClient/async-http-client 这个吗?看起来不像 Android 用的东西,
    >> It's built on top of Netty and currently requires JDK8.

    还是推荐 Retrofit + RxJava 这一套,而且最好不要想着读它们的源码。
    royliu
        9
    royliu  
    OP
       2017 年 1 月 17 日
    @icris 这个是在 apache 的 HttpClient 基础上为 Android 封装的网络请求库,前几年比较火,刚学 Android 的时候就是用的这个。现在项目中用的 Retrofit + RxJava ,确实很好用。以前只知道他们的用法并没有深究过内部的实现,现在想把这几个网络请求库源码都翻出来看看。
    > 而且最好不要想着读它们的源码。
    为啥不要想着读 Retrofit + RxJava 源码呢?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1117 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 53ms UTC 18:12 PVG 02:12 LAX 11:12 JFK 14:12
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86