当前位置:   article > 正文

浅析OkHttp_okhttp请求回调是在子线程中吗

okhttp请求回调是在子线程中吗
本文将从源码角度浅析OkHttp,主要在于OkHttp处理的流程,所以叫浅析。具体的用法不是本文的重点。通过对OkHttp的基本用法来一步步探索OkHttp的运行流程。
OkHttp实际上是利用线程池来处理子线程的任务即网络请求,处理得到的结果是运行在子线程中,所以我们需要对数据通过Handler等方法处理到主线程。OkHttp利用的线程池是类似于CacheThreadPool的,具体的创建方法为:
  1. public synchronized ExecutorService executorService() {
  2. if (executorService == null) {
  3. executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  5. }
  6. return executorService;
  7. }
既然用到了线程池,所以这也是OkHttp也具有线程池的优点:重用线程池中的线程,我们可以同时创建许多个线程来请求网络,且不会带来额外的性能开销。
从OkHttp的基本用法,我们一步步分析流程,OkHttp的基本Get用法:
  1. //创建okHttpClient对象
  2. OkHttpClient mOkHttpClient = new OkHttpClient(); //第一步
  3. //创建一个Request
  4. final Request request = new Request.Builder()
  5. .url("https://github.com/hongyangAndroid")
  6. .build(); //第二步
  7. //new call
  8. Call call = mOkHttpClient.newCall(request); //第三步
  9. //请求加入调度
  10. call.enqueue(new Callback() //第四步
  11. {
  12. @Override
  13. public void onFailure(Request request, IOException e)
  14. {
  15. }
  16. @Override
  17. public void onResponse(final Response response) throws IOException
  18. {
  19. //String htmlStr = response.body().string();
  20. }
  21. });

首先第一二步是定义两个对象OkHttpClient和Request。
OkHttpClient为保存网络配置的‘javabean‘,可以配置连接时间,读取时间等,最主要的是配置插值器Interceptor(OkHttp巧妙的运用了插值器功能,代码值得借鉴,关于Interceptor类,稍后重点分析)
Request类为保存请求数据的’javabean‘,可以配置url,header,请求方法等。
通过第三步的newCall方法我们创建了一个RealCall类,该类实际上是一个Runnable
  1. /**
  2. * Prepares the {@code request} to be executed at some point in the future.
  3. */
  4. @Override public Call newCall(Request request) {
  5. return new RealCall(this, request, false /* for web socket */);
  6. }

第四步调用RealCall类的异步请求方法enqueue请求数据。下面我们跟着该方法,一步一步分析流程
首先来看RealCall的enqueue方法:
  1. @Override public void enqueue(Callback responseCallback) {
  2. synchronized (this) {
  3. if (executed) throw new IllegalStateException("Already Executed");
  4. executed = true;
  5. }
  6. captureCallStackTrace();
  7. client.dispatcher().enqueue(new AsyncCall(responseCallback)); //主要看这一步
  8. }

调用OkHttpClient类中的dispatcher()方法返回一个Dispatcher对象,然后调用其enqueue()方法
  1. synchronized void enqueue(AsyncCall call) {
  2. //如果正在运行的call小于设置的最大值,那么将该Runnable加入到运行列表并执行,否则加入到等待列表
  3. if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
  4. runningAsyncCalls.add(call);
  5. executorService().execute(call);
  6. } else {
  7. readyAsyncCalls.add(call);
  8. }
  9. }

创建的线程池enecutorService()理论上可以容纳无穷多个Runnable,我们通过maxRequests来控制线程池中的数量。
通过executorService的execute()方法,我们会执行AsyncCall中的run方法,而AsyncCall是继承NamedRunnable的,NamedRunnable类:
  1. public abstract class NamedRunnable implements Runnable {
  2. protected final String name;
  3. public NamedRunnable(String format, Object... args) {
  4. this.name = Util.format(format, args);
  5. }
  6. @Override public final void run() {
  7. String oldName = Thread.currentThread().getName();
  8. Thread.currentThread().setName(name);
  9. try {
  10. execute();
  11. } finally {
  12. Thread.currentThread().setName(oldName);
  13. }
  14. }
  15. protected abstract void execute();
  16. }

AsyncCall类会执行execute方法:

  1. @Override protected void execute() {
  2. boolean signalledCallback = false;
  3. try {
  4. Response response = getResponseWithInterceptorChain();
  5. if (retryAndFollowUpInterceptor.isCanceled()) {
  6. signalledCallback = true;
  7. //通过回调就能得到结果
  8. responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
  9. } else {
  10. signalledCallback = true;
  11. //通过回调就能得到结果了,但是是在子线程
  12. responseCallback.onResponse(RealCall.this, response);
  13. }
  14. } catch (IOException e) {
  15. if (signalledCallback) {
  16. // Do not signal the callback twice!
  17. Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
  18. } else {
  19. responseCallback.onFailure(RealCall.this, e);
  20. }
  21. } finally {
  22. client.dispatcher().finished(this);
  23. }
  24. }

通过 getResponseWithInterceptorChain()方法获取到从服务器返回的数据,这里面主要是对Interceptor类进行添加,来看一下方法体:
  1. Response getResponseWithInterceptorChain() throws IOException {
  2. // Build a full stack of interceptors.
  3. List<Interceptor> interceptors = new ArrayList<>();
  4. interceptors.addAll(client.interceptors());
  5. interceptors.add(retryAndFollowUpInterceptor);
  6. interceptors.add(new BridgeInterceptor(client.cookieJar()));
  7. interceptors.add(new CacheInterceptor(client.internalCache()));
  8. interceptors.add(new ConnectInterceptor(client));
  9. if (!forWebSocket) {
  10. interceptors.addAll(client.networkInterceptors());
  11. }
  12. interceptors.add(new CallServerInterceptor(forWebSocket));
  13. Interceptor.Chain chain = new RealInterceptorChain(
  14. interceptors, null, null, null, 0, originalRequest);
  15. return chain.proceed(originalRequest);
  16. }

将Interceptor添加到ArrayList表中进行顺序执行,通过OkHttpClient的addInterceptor()方法逐步添加自定义的Interceptor,最后通过CallServerInterceptor方法获取到最终的网络数据。最后看一眼RealInterceptorChain类:
  1. /**
  2. * A concrete interceptor chain that carries the entire interceptor chain: all application
  3. * interceptors, the OkHttp core, all network interceptors, and finally the network caller.
  4. */
  5. public final class RealInterceptorChain implements Interceptor.Chain {
  6. private final List<Interceptor> interceptors;
  7. private final StreamAllocation streamAllocation;
  8. private final HttpCodec httpCodec;
  9. private final Connection connection;
  10. private final int index;
  11. private final Request request;
  12. private int calls;
  13. public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
  14. HttpCodec httpCodec, Connection connection, int index, Request request) {
  15. this.interceptors = interceptors;
  16. this.connection = connection;
  17. this.streamAllocation = streamAllocation;
  18. this.httpCodec = httpCodec;
  19. this.index = index;
  20. this.request = request;
  21. }
  22. @Override public Connection connection() {
  23. return connection;
  24. }
  25. public StreamAllocation streamAllocation() {
  26. return streamAllocation;
  27. }
  28. public HttpCodec httpStream() {
  29. return httpCodec;
  30. }
  31. @Override public Request request() {
  32. return request;
  33. }
  34. @Override public Response proceed(Request request) throws IOException {
  35. return proceed(request, streamAllocation, httpCodec, connection);
  36. }
  37. public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
  38. Connection connection) throws IOException {
  39. if (index >= interceptors.size()) throw new AssertionError();
  40. calls++;
  41. // If we already have a stream, confirm that the incoming request will use it.
  42. if (this.httpCodec != null && !sameConnection(request.url())) {
  43. throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
  44. + " must retain the same host and port");
  45. }
  46. // If we already have a stream, confirm that this is the only call to chain.proceed().
  47. if (this.httpCodec != null && calls > 1) {
  48. throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
  49. + " must call proceed() exactly once");
  50. }
  51. // Call the next interceptor in the chain.
  52. RealInterceptorChain next = new RealInterceptorChain(
  53. interceptors, streamAllocation, httpCodec, connection, index + 1, request);
  54. Interceptor interceptor = interceptors.get(index);
  55. Response response = interceptor.intercept(next);
  56. // Confirm that the next interceptor made its required call to chain.proceed().
  57. if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
  58. throw new IllegalStateException("network interceptor " + interceptor
  59. + " must call proceed() exactly once");
  60. }
  61. // Confirm that the intercepted response isn't null.
  62. if (response == null) {
  63. throw new NullPointerException("interceptor " + interceptor + " returned null");
  64. }
  65. return response;
  66. }
  67. private boolean sameConnection(HttpUrl url) {
  68. return url.host().equals(connection.route().address().url().host())
  69. && url.port() == connection.route().address().url().port();
  70. }
  71. }

其中的proceed()方法,通过遍历Interceptor列表,依次执行各自的intercept()方法,在Interceptor的实现类中,一定要调用proceed方法依次遍历剩余Interceptor。这种方法非常巧妙的获取到列表中的最后一个值,并且第一个Interceptor可以获取到最后一个Interceptor中的值,并且可以依次加载中间的类。刚开始看这段代码比较迷惑,非常棒,在针对插值器方法的时候,非常有效简洁明了,其中一个Interceptor:
  1. public final class ConnectInterceptor implements Interceptor {
  2. public final OkHttpClient client;
  3. public ConnectInterceptor(OkHttpClient client) {
  4. this.client = client;
  5. }
  6. @Override public Response intercept(Chain chain) throws IOException {
  7. RealInterceptorChain realChain = (RealInterceptorChain) chain;
  8. Request request = realChain.request();
  9. StreamAllocation streamAllocation = realChain.streamAllocation();
  10. // We need the network to satisfy this request. Possibly for validating a conditional GET.
  11. boolean doExtensiveHealthChecks = !request.method().equals("GET");
  12. HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
  13. RealConnection connection = streamAllocation.connection();
  14. return realChain.proceed(request, streamAllocation, httpCodec, connection);
  15. }
  16. }

这样整个OkHttp异步请求网络的流程就走完了,项目中异步请求用的较多。
总结:OkHttp利用线程池实现异步操作,通过Interceptor插值器来获取数据,处理数据

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/465175
推荐阅读
相关标签
  

闽ICP备14008679号