You must learn the OkHttp, take you on a fast car

Primer

OkHttp well-known third-party network Framework SDK, easy to use, excellent performance, but the kernel is not simple, this series of articles, a rarity hard core knowledge points to explain in detail. What is hard core, that is, in order to in-depth research, you are definitely not around the past knowledge point

Body outline

  • What OkHttp that?
  • OkHttp how to use?
  • One of the core classes OkHttp Source: Detailed distributor
  • One of the core classes OkHttp Source: Interceptor Description

A. Text

What is 1.OkHttp

OkHttp is a very popular network programming framework, an open source company by an industry giant guy Square, many other popular frameworks such as the underlying retrofit also okhttp, but uses annotations reflection of its dynamic agent is encapsulated. Popular version: 3.10.0, the latest version: 4.0.1, but will be achieved from the java language changed kotlin.

Frame relative to other networks, has the following advantages:

  • Support Spdy, Http1.X, Http2, Quic and WebSocket
  • Multiplexing connection pool underlying TCP (Socket), a request to reduce latency
  • Seamless support GZIP reduce data traffic
  • Duplicate response data buffer to reduce network requests
  • Other automatic retry request failed ip host automatically redirected
2.OkHttp how to use

Add gradle dependence

dependencies {
   ....
    implementation ("com.squareup.okhttp3:okhttp:4.0.1")
}

Java calls (synchronous request, asynchronous requests)

public class MyRequest {
    /**
     * 异步请求
     */
    public void sendReqAsync() {
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request=newRequest.Builder().url("http://www.baidu.com").build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call,@NotNull IOException e) {
                Log.d("sendReqTag", "onFailure:"+e.getLocalizedMessage());
            }

            @Override
            public void onResponse(@NotNull Call call,@NotNull Response response) throws IOException {
                String s = new String().concat(response.code() +"\n")
                        .concat(response.message()+"\n")
                        .concat(response.body().string());
                Log.d("sendReqTag","onSuccess\n "+ s);
            }
        });
    }
    /**
     * 同步请求
     */
    public void sendReqSync() {
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().url("http://www.baidu.com").build();
        Call call = client.newCall(request);
        try {
            Response response = call.execute();
            String s = new String().concat(response.code() + "\n")
                    .concat(response.message() + "\n")
                    .concat(response.body().string());
            Log.d("sendReqTag","onSuccess\n "+s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

OkHttp generally simple to use as above, wherein there are some details to note:

1, the application layer OkHttp, inevitably involve four key elements:

  • OkHttpClient type (client instance produce OkHttp)
  • Request class (encapsulation request)
  • Call type (network task package, and decide whether to perform synchronous or asynchronous execution, note that synchronization -
    the request can not be placed in the main thread, the request may be asynchronous)
  • Response class (callback after the network task execution)

2. Perform network requests must apply INTERNET permission in the manifest, or will throw an exception.

3, a request to perform a complete out, the process shown below:
You must learn the OkHttp, take you on a fast car

One of the core classes OkHttp Source: Detailed distributor

上述,提到Call类,可以选择性执行 同步或者异步请求,但是无论同步异步,都一定会经过一个门户:"分发器" : 索引进源码(okhttp v3.10.0):
You must learn the OkHttp, take you on a fast car
You must learn the OkHttp, take you on a fast car

虽然用户不需要直接操作分发器,但是 分发器,作为 OkHttp架构的一个门户层,是所有请求的必经之路,其中的代码还是有必要了解细节的。

3.同步请求

进入 分发器Dispatcher之后, 会执行 getResponseWithInterceptorChain()来执行这个 Call任务,得到一个 Response,其中的细节分为两步:

1、client.dispatcher().executed(this);,进入源码可以看到 仅仅是执行了runningSyncCalls.add(call);,将call对象加入到了一个双端队列 Deque<RealCall>runningSyncCalls 中。
2、 getResponseWithInterceptorChain() 是执行网络请求的核心内容,涉及到拦截器,在这一节上暂时不详述。

同步请求的执行步骤十分简单,将任务加入到 runningSyncCalls列表,并且直接执行核心方法,同步阻塞拿到response。

4.异步请求

异步请求进入分发器之后,
You must learn the OkHttp, take you on a fast car
可能会被加入到 Deque<AsyncCall>runningAsyncCalls 这么一个双端队列中,然后 executorService().execute(call);实际上是用了线程池来执行了这个异步任务。但是,请注意(还是刚才的enqueue方法代码)这里有一个判断条件 if分支 :
You must learn the OkHttp, take you on a fast car
这个条件是否满足,将会直接决定是直接执行这个任务,还是将任务加入到 readyAsyncCalls 双端队列.

那么设置这个条件的目的是什么呢?从变量命名来看: runningAsyncCalls 执行中的异步任务 runningCallsForHost 同一个域名正在执行的任务数 readyAsyncCalls 预备执行的任务队列(尚未执行)

当正在执行的任务数小于最大值(默认为64)并且,同一个域名正在请求的任务数小于最大值(默认5)时,才会立即执行,否则,这个任务会被加入到 readyAsyncCalls中等待安排。

那么问题来了,readyAsyncCalls中的任务什么时候会被执行?追踪代码:追踪 readyAsyncCalls 的使用代码,找到 遍历这个队列的地方:
You must learn the OkHttp, take you on a fast car
继续追踪,找到了这个 finish方法:
You must learn the OkHttp, take you on a fast car
继续追踪finish在哪里调用的,找到两处:
You must learn the OkHttp, take you on a fast car
You must learn the OkHttp, take you on a fast car
所以,得出结论:在一个任务(无论同步还是异步)结束之后,分发器中的异步任务,存在两个队列,一个 running队列,一个 ready队列,当 running队列的size小于最大值,并且同一个域名正在执行的任务数小于最大值时,可以直接加入到running队列,立即执行。如果不满足这条件,这个异步任务就会被加入到 ready队列.

在任意一个任务( 无论同步或是异步任务)执行完毕( 无论成败)之后,就会遍历 ready队列,每次从 ready队列中取出一个任务,判断同时执行的异步任务数是否达到上限,并且同一主机的访问数是否达到上限,如果都满足,就加入到running队列,并且立即执行,不满足,就停止遍历。周而复始,直到所有的异步任务都执行完。

文字不够形象,画个图表示。
You must learn the OkHttp, take you on a fast car

关于okhttp的分发器Dispatcher用到的线程池

同步请求,没有用到线程池。
You must learn the OkHttp, take you on a fast car

但是异步请求的代码中,有这么一句。
You must learn the OkHttp, take you on a fast car

我们知道,为什么这里会用到线程池呢?
1.观察 同步或者异步的call的实例
You must learn the OkHttp, take you on a fast car
那么这个 Call是什么?它是一个接口,它的唯一实现类是 RealCall,
You must learn the OkHttp, take you on a fast car
RealCall中,异步请求的执行方法,enqueue() 其实是交给了 分发器一个AsyncCall对象,它继承自 NamedRunnable可命名的 Runnable任务。所以,这里可以用 线程池 ExecutorService来执行这个Runnable.

进一步观察这个线程池的细节:
You must learn the OkHttp, take you on a fast car
它是一个核心线程数为0的线程池,并且使用了一个无容量的阻塞队列作为参数。其实也不不必自己去创建线程池,而可以直接使用 Executors.newCachedThreadPool(); 来创建,效果一样。线程池,系统提供了有多种默认实现
You must learn the OkHttp, take you on a fast car

为什么okhttp偏偏选择了这一种?

为了实现最大并发量。

详解如下:既然这里提到了线程池,那么就把线程池的基本机制整理一下:
You must learn the OkHttp, take you on a fast car
线程池的构造函数中,有一个阻塞队列参数。
You must learn the OkHttp, take you on a fast car
它有3个实现类:ArrayBlockingDeque/ LinkedBlockingDeque / SynchronousQueue 是我们线程池经常用的。前面2个都是有容量的,而第三个是无容量的,加入进去,一定会失败。而参照上面线程池的工作流程图,如果加入失败,就会尝试去非核心线程执行任务。这样,便保证了每一个提交进来的异步任务,都会立即尝试去执行,而不是塞入等待队列中等待空闲线程,从而确保了 异步任务的并发。

OkHttp源码核心类之一:拦截器简述

上面讲解分发器的时候,提到了 RealCall类的 getResponseWithInterceptorChain()方法。它是一个网络请求执行的真正核心方法。进入方法:
You must learn the OkHttp, take you on a fast car

  • 新建一个拦截器List,并且放入各种拦截器对象
  • 将拦截器list,交给RealInterceptorChain,进行责任链模式的调用,最终得出Response.

First explain the chain of responsibility pattern, which is 21 kinds of basic design patterns, behavior patterns of one. The following cases can explain it:
You must learn the OkHttp, take you on a fast car
When a group of state-owned enterprises to purchase equipment, according to the view of the whole task flow, there are five objects, can result in time affect procurement task starts on the procurement process, from in turn is responsible for the procurement process to the next. General manager, he did not care about the people below how to operate, he only cares about the final result. As this case said, okhttp responsibility chain mode, the user does not need to be concerned about this request in the end what went through the process, he only knew, I gave request, you have to give me a response, and the course, play a role in various types of interceptors, users do not need to know, so that you know to reach the minimum principles of object-oriented program development.

And, these interceptors, it is the core of okhttp, the next article will explain in detail.

III. Conclusion

This article is okhttp the opening, if you want a detailed explanation of every detail okhttp, each article will be very tedious and boring, so I chose an important node focuses on. Like to lose ground to conquer the world, occupying the first positions, and then attempt to expand, step by step, slowly and surely, to long-term development

Guess you like

Origin blog.51cto.com/14541311/2438941