美文网首页
OkHttp源码解析

OkHttp源码解析

作者: 左大人 | 来源:发表于2018-11-21 15:06 被阅读0次

    image.png

    序言

    上一篇文章介绍了Retrofit的原理,今天,我们就来探究一下OkHttp的原理。Retrofit是对OkHttp做封装,真正发送网络请求的就是OkHttp框架。
    使用Retrofit框架过程中,对OkHttp最直观的认识就是OkHttpClient,这篇文章会按如下目录展开介绍:

    • OkHttp的用法
    • OkHttp在Retrofit中的使用
    • OkHttp的原理
    • 对比OkHttp与其他网络库
    • 总结

    OkHttp的用法

    本文基于OkHttp3.10.0版本进行介绍。

    1. 首先添加OkHttp依赖
    implementation("com.squareup.okhttp3:okhttp:3.10.0")
    

    如果项目中添加了Retrofit2依赖,就不用再添加OkHttp3的依赖,因为Retrofit2库使用到了OkHttp3,并且已经添加了OkHttp3的依赖,所以不用我们重复添加。

    1. 使用方法
    //创建OkHttpClient对象
    OkHttpClient client = new OkHttpClient();
    
    String run(String url) throws IOException {
       //创建Request请求对象
      Request request = new Request.Builder()
          .url(url)
          .build();
    
       //创建Call对象,并执行同步获取网络数据
      Response response = client.newCall(request).execute();
      return response.body().string();
    }
    

    总结一下,OkHttp的使用步骤如下:

    • 创建OkHttpClient对象
    • 创建Request对象
    • 创建Call对象
    • 通过Call对象发起请求,同步请求调用call.execute方法,异步请求调用call.enqueue方法

    OkHttp在Retrofit中的使用

    结合之前的一篇文章Retrofit源码解析,我们来看一下在Retrofit中怎样使用OkHttp。

    1. 创建OkHttpClient对象
      在初始化Retrofit对象的时候,我们会传入一个OkHttpClient对象:
    DeviceRetrofit() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(Config.HTTP_TIMEOUT, TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(true)
                .addInterceptor(new DeviceInterceptor())
                .addInterceptor(OkHttpUtils.getHttpInterceptor(TAG))
                .build();
    
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(Config.DEVICE_HOST)
                .addConverterFactory(JacksonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        mService = retrofit.create(DeviceService.class);
    }
    

    这里完成了第一步,创建OkHttpClient对象。

    1. 创建Request对象
      当我们通过Retrofit发起一个请求的时候,在ServiceMethod中会创建一个okhttp3.Request对象:
    /**
     * 创建Call对象
     */
    private okhttp3.Call createRawCall() throws IOException {
      Request request = serviceMethod.toRequest(args);
      okhttp3.Call call = serviceMethod.callFactory.newCall(request);
      if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
      }
      return call;
    }
    
    /**
     * 创建Request对象
     */
    Request toRequest(Object... args) throws IOException {
      RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
          contentType, hasBody, isFormEncoded, isMultipart);
    
      @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
      ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    
      int argumentCount = args != null ? args.length : 0;
      if (argumentCount != handlers.length) {
        throw new IllegalArgumentException("Argument count (" + argumentCount
            + ") doesn't match expected count (" + handlers.length + ")");
      }
    
      for (int p = 0; p < argumentCount; p++) {
        handlers[p].apply(requestBuilder, args[p]);
      }
    
      return requestBuilder.build();
    }
    

    这里完成了第二步,创建了一个Request对象。

    1. 创建Call对象
      第二步的代码中,有一个createRawCall方法,它会从callFactory工厂中创建一个Call对象,之前说过,callFactory就是OkHttpClient,所以看OkHttpClient的newCall方法:
    @Override public Call newCall(Request request) {
      return RealCall.newRealCall(this, request, false /* for web socket */);
    }
    

    这里完成了第三步,创建了一个RealCall对象。

    1. 调用Call的execute方法
      在RxJavaCallAdapterFactory.CallOnSubscribe.call方法中,会调用call.execute()发送同步请求:
    static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
      private final Call<T> originalCall;
    
      CallOnSubscribe(Call<T> originalCall) {
        this.originalCall = originalCall;
      }
    
      @Override public void call(final Subscriber<? super Response<T>> subscriber) {
        // Since Call is a one-shot type, clone it for each new subscriber.
        final Call<T> call = originalCall.clone();
    
        // Attempt to cancel the call if it is still in-flight on unsubscription.
        subscriber.add(Subscriptions.create(new Action0() {
          @Override public void call() {
            call.cancel();
          }
        }));
    
        try {
          Response<T> response = call.execute();
          if (!subscriber.isUnsubscribed()) {
            subscriber.onNext(response);
          }
        } catch (Throwable t) {
          Exceptions.throwIfFatal(t);
          if (!subscriber.isUnsubscribed()) {
            subscriber.onError(t);
          }
          return;
        }
    
        if (!subscriber.isUnsubscribed()) {
          subscriber.onCompleted();
        }
      }
    }
    

    这里就完成了第四步,调用call.execute方法。

    可见,Retrofit中确实是按照OkHttp3的四个步骤进行使用。

    OkHttp的原理

    上面介绍了OkHttp的使用方法,以及Retrofit中怎样使用OkHttp。那么下面我们就来分析一下OkHttp的原理,OkHttp是怎样发送Http请求的?我们还是按照这四个步骤进行分析。

    1. 创建OkHttpClient对象
      我们看一下OkHttpClient的实现:
    public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
      static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
          Protocol.HTTP_2, Protocol.HTTP_1_1);
    
      static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
          ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
    
      final Dispatcher dispatcher; //请求分发器
      final @Nullable Proxy proxy;
      final List<Protocol> protocols; //支持的协议,默认http1.1和http2
      final List<ConnectionSpec> connectionSpecs;
      final List<Interceptor> interceptors; //用户设置的拦截器
      final List<Interceptor> networkInterceptors;
      final EventListener.Factory eventListenerFactory; //请求事件监听器工厂
      final ProxySelector proxySelector;
      final CookieJar cookieJar; //可设置往请求头中加入cookie信息
      final @Nullable Cache cache; //可设置是否缓存请求Response策略
      final @Nullable InternalCache internalCache; //OkHttp3.0之后使用cache,不再使用此成员变量
      final SocketFactory socketFactory;
      final @Nullable SSLSocketFactory sslSocketFactory;
      final @Nullable CertificateChainCleaner certificateChainCleaner;
      final HostnameVerifier hostnameVerifier;
      final CertificatePinner certificatePinner;
      final Authenticator proxyAuthenticator;
      final Authenticator authenticator;
      final ConnectionPool connectionPool;
      final Dns dns;
      final boolean followSslRedirects;
      final boolean followRedirects;
      final boolean retryOnConnectionFailure;
      final int connectTimeout; //默认连接超时时间10s
      final int readTimeout; //默认读取超时时间10s
      final int writeTimeout; //默认写入超时时间10s
      final int pingInterval; 
        
      //省略其他代码
    }
    

    部分关键的成员标了注释,各位同学可以看一下。着重关注一下Dispatcher类,它是网络请求分发器,同步请求和异步请求会做不同的分发处理,后面会详细介绍该类。

    1. 创建Request对象
      看一下Request的实现:
    /**
     * An HTTP request. Instances of this class are immutable if their {@link #body} is null or itself
     * immutable.
     */
    public final class Request {
      final HttpUrl url;
      final String method;
      final Headers headers;
      final @Nullable RequestBody body;
      final Object tag;
    
      private volatile CacheControl cacheControl; // Lazily initialized.
    
      Request(Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers.build();
        this.body = builder.body;
        this.tag = builder.tag != null ? builder.tag : this;
      }
      
      //省略其他代码
    }
    

    从注释中可以知道,这个类代表Http请求,其中包含了Http请求所需的信息。

    • url:请求地址
    • methdo:请求类型,如GET、POST、DELETE、PATCH、PUT等
    • headers:请求头信息
    • body:请求体
    • tag:标签

    我们在看一下Header类的结构:

    public final class Headers {
      private final String[] namesAndValues;
    
      Headers(Builder builder) {
        this.namesAndValues = builder.namesAndValues.toArray(new String[builder.namesAndValues.size()]);
      }
    
      //省略其他代码
    }
    

    可以看到Headers类中通过一个字符串数组保存头信息,保存方式如下{key1, value1, key2, value2, ...}

    再看一下RequestBody类的结构:

    public abstract class RequestBody {
      /** Returns the Content-Type header for this body. */
      public abstract @Nullable MediaType contentType();
    
      /**
       * Returns the number of bytes that will be written to {@code sink} in a call to {@link #writeTo},
       * or -1 if that count is unknown.
       */
      public long contentLength() throws IOException {
        return -1;
      }
    
      /** Writes the content of this request to {@code sink}. */
      public abstract void writeTo(BufferedSink sink) throws IOException;
    
      //省略其他代码
    }
    

    RequestBody是一个抽象类,其中有两个抽象方法:

    • writeTo方法:用于把请求体的内容写入到sink(发送请求到服务器的对象)
    • contentType方法:标志请求体内容的类型。

    Request相关内容介绍完毕,接下来看一下创建Call部分。

    1. 创建Call对象
      Call对象,我们可以理解为一次网络请求的封装,一个Call对象只能被执行一次。那么,是如果保证只能被执行一次的特性呢?
      上面提到过,Retrofit会为一次请求创建一个RealCall对象:
    final class RealCall implements Call {
      final OkHttpClient client;
      final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
    
      /**
       * There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward.
       * This will be set after we create the call instance then create the event listener instance.
       */
      private EventListener eventListener;
    
      /** The application's original request unadulterated by redirects or auth headers. */
      final Request originalRequest;
      final boolean forWebSocket;
    
      // Guarded by this.
      private boolean executed;
    
      private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
        this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
      }
    
      @Override public Response execute() throws IOException {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        try {
          client.dispatcher().executed(this);
          Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } catch (IOException e) {
          eventListener.callFailed(this, e);
          throw e;
        } finally {
          client.dispatcher().finished(this);
        }
      }
      
      @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    
      //省略其他代码
    }
    

    我们可以看到,RealCall中有个布尔型的变量executed,标志该Call是否已经执行了。
    在execute和enqueue两个方法中都会校验executed,这就保证了一个Call只能执行一次

    1. 调用call.execute或call.enqueue
      再看execute和enqueue两个方法,都会调用Dispatcher对应的方法。那就看看Dispatcher的实现:
    public final class Dispatcher {
      private int maxRequests = 64;
      private int maxRequestsPerHost = 5;
      private @Nullable Runnable idleCallback;
    
      /** Executes calls. Created lazily. */
      private @Nullable ExecutorService executorService;
    
      /** Ready async calls in the order they'll be run. */
      private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    
      /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
      private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
    
      /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
      private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    
      public Dispatcher(ExecutorService executorService) {
        this.executorService = executorService;
      }
    
      public Dispatcher() {
      }
    
      /** Used by {@code Call#execute} to signal it is in-flight. */
      synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
      }
    
      synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
      }
    
      //省略其他代码
    }
    

    Dispatcher中有几个成员变量,依次介绍一下:

    • maxRequests:表示异步请求支持的最大并发请求数
    • maxRequestsPerHost:表示每个Host支持的最大并发请求数,Host可以理解为baseUrl
    • idleCallback:分发器闲置回调,即分发器中没有正在执行的请求和准备执行的请求,就会回调idleCallback.run方法
    • executorService:线程池,用于管理异步请求的线程
    • readyAsyncCalls:处于准备状态的异步请求队列
    • runningAsyncCalls:正在执行的异步请求队列
    • runningSyncCalls:正在执行的同步请求队列

    着重关注两个异步请求队列,什么时候会进入异步准备队列,什么时候又会进入异步执行队列呢?

    runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost
    

    满足上面条件,即异步线程数量已经超过最大请求数,或者单个Host的异步请求数超过最大请求数,就会进入异步准备队列,否则直接进入异步执行队列

    我们再看Dispatcher的executed和enqueue方法,发现executed方法很简单:

    /** Used by {@code Call#execute} to signal it is in-flight. */
    synchronized void executed(RealCall call) {
      runningSyncCalls.add(call);
    }
    

    这里只是把同步请求加入同步执行队列中,并没有具体的请求执行操作。那么这个执行操作在哪里呢?
    我们看回RealCall的execute方法:

    @Override public Response execute() throws IOException {
      synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
      }
      captureCallStackTrace();
      eventListener.callStart(this);
      try {
        client.dispatcher().executed(this);
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        return result;
      } catch (IOException e) {
        eventListener.callFailed(this, e);
        throw e;
      } finally {
        client.dispatcher().finished(this);
      }
    }
    

    在调用了Dispatcher.executed方法后,会调用getResponseWithInterceptorChain()方法,那么可以肯定,这个方法就是真正执行请求的地方。
    再看一下异步请求,RealCall的enqueue方法中,调用Dispatcher.enqueue方法时,会创建一个AsyncCall对象作为参数传入。那我们看一下AsyncCall的实现:

    final class AsyncCall extends NamedRunnable {
      private final Callback responseCallback;
    
      AsyncCall(Callback responseCallback) {
        super("OkHttp %s", redactedUrl());
        this.responseCallback = responseCallback;
      }
    
      String host() {
        return originalRequest.url().host();
      }
    
      Request request() {
        return originalRequest;
      }
    
      RealCall get() {
        return RealCall.this;
      }
    
      @Override protected void execute() {
        boolean signalledCallback = false;
        try {
          Response response = getResponseWithInterceptorChain();
          if (retryAndFollowUpInterceptor.isCanceled()) {
            signalledCallback = true;
            responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
          } else {
            signalledCallback = true;
            responseCallback.onResponse(RealCall.this, response);
          }
        } catch (IOException e) {
          if (signalledCallback) {
            // Do not signal the callback twice!
            Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
          } else {
            eventListener.callFailed(RealCall.this, e);
            responseCallback.onFailure(RealCall.this, e);
          }
        } finally {
          client.dispatcher().finished(this);
        }
      }
    }
    

    在AsyncCall的execute方法中,也会调用getResponseWithInterceptorChain()方法。

    也就是说,不管是同步还是异步请求,都是通过getResponseWithInterceptorChain()方法真正执行请求的

    接下来,当然是看getResponseWithInterceptorChain方法的实现:

    Response getResponseWithInterceptorChain() throws IOException {
      // Build a full stack of interceptors.
      List<Interceptor> interceptors = new ArrayList<>();
      interceptors.addAll(client.interceptors());
      interceptors.add(retryAndFollowUpInterceptor);
      interceptors.add(new BridgeInterceptor(client.cookieJar()));
      interceptors.add(new CacheInterceptor(client.internalCache()));
      interceptors.add(new ConnectInterceptor(client));
      if (!forWebSocket) {
        interceptors.addAll(client.networkInterceptors());
      }
      interceptors.add(new CallServerInterceptor(forWebSocket));
    
      Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
          originalRequest, this, eventListener, client.connectTimeoutMillis(),
          client.readTimeoutMillis(), client.writeTimeoutMillis());
    
      return chain.proceed(originalRequest);
    }
    

    这个方法中,先得到一个interceptors列表,其中包含的元素有:

    1. 用户设置的interceptor列表
    2. RetryAndFollowUpInterceptor:错误重试和重定向拦截器
    3. BridgeInterceptor:把用户的request转换为Http的request,把Http的response转换为用户需要response的转换桥拦截器
    4. CacheInterceptor:处理Response缓存的拦截器
    5. ConnectInterceptor:建立服务器连接的拦截器
    6. 用户设置的networkInterceptors列表
    7. CallServerInterceptor:真正向服务器发送请求并且得到响应的拦截器

    然后创建一个RealInterceptorChain对象,继而调用其proceed方法。
    RealInterceptorChain实现了Interceptor.Chain接口,先看一下接口定义:

    /**
     * Observes, modifies, and potentially short-circuits requests going out and the corresponding
     * responses coming back in. Typically interceptors add, remove, or transform headers on the request
     * or response.
     */
    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
    
        Response proceed(Request request) throws IOException;
    
        /**
         * Returns the connection the request will be executed on. This is only available in the chains
         * of network interceptors; for application interceptors this is always null.
         */
        @Nullable Connection connection();
    
        Call call();
    
        int connectTimeoutMillis();
    
        Chain withConnectTimeout(int timeout, TimeUnit unit);
    
        int readTimeoutMillis();
    
        Chain withReadTimeout(int timeout, TimeUnit unit);
    
        int writeTimeoutMillis();
    
        Chain withWriteTimeout(int timeout, TimeUnit unit);
      }
    }
    

    再看RealInterceptorChain的定义:

    public final class RealInterceptorChain implements Interceptor.Chain {
      private final List<Interceptor> interceptors;
      private final StreamAllocation streamAllocation;
      private final HttpCodec httpCodec;
      private final RealConnection connection;
      private final int index;
      private final Request request;
      private final Call call;
      private final EventListener eventListener;
      private final int connectTimeout;
      private final int readTimeout;
      private final int writeTimeout;
      private int calls;
    
      public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
          HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
          EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
        this.interceptors = interceptors;
        this.connection = connection;
        this.streamAllocation = streamAllocation;
        this.httpCodec = httpCodec;
        this.index = index;
        this.request = request;
        this.call = call;
        this.eventListener = eventListener;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
      }
    
      //省略部分代码
      
      public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
            connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
            writeTimeout);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException("network interceptor " + interceptor
              + " must call proceed() exactly once");
        }
    
        // Confirm that the intercepted response isn't null.
        if (response == null) {
          throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
    
        if (response.body() == null) {
          throw new IllegalStateException(
              "interceptor " + interceptor + " returned a response with no body");
        }
    
        return response;
      }
    }
    

    我们着重看proceed方法,proceed方法我用一张流程图来总结:


    image.png

    通过这张图,可以很清晰的看到执行的流程:
    通过RealInterceptorChain一层一层调用各interceptor的intercept方法,并且在此过程中可以处理request,比如往其中添加参数,或者做一些其他操作。一直到CallServerInterceptor,它是最后一个拦截器,真正用来执行网络请求,从服务器获取Response。然后把Response一层一层网上传递,在此过程中,可以对Response做一定的处理
    这个过程用到了责任链模式,以链式调用,每一个节点可以执行不同的逻辑,各节点之间解耦,扩展性强,可以随意添加节点。

    想知道怎样执行网络请求的同学,可以自行研究各个Interceptor,尤其是CallServerInterceptor,它是真正执行网络请求的地方。主要是调用了Http1Codec.flushRequest方法,继而调用BufferedSink.flush方法,之后的就留给各位同学自己去看了。

    最后得到的Response对象交给Retrofit进行转换适配,到这里OkHttp的原理分析完毕。

    对比OkHttp与其他网络库

    这里主要对比几个常用的网络扩,包括android-async-http、volley、OkHttp和Retrofit。

    1. android-async-http(loopj)
    • 基于HttpClient
    • 自动请求重试
    • 持久化cookie,保存在sp中
    • 作者已经停止对项目维护,因此不推荐在项目中使用
    1. volley(Google)
    • 基于HttpURLConnection
    • 封装图片框架,支持图片加载
    • 与Activity生命周期的联动,Activit结束时取消所有的网络请求
    • 适合数据量小,频率高的请求,不适合上传或下载大文件,原因:线程池默认大小是4,Request.getBody()返回的是字节数组,也就是对于Post或Put请求,会把传输的数据一股脑读到内存中,很容易出现oom
    1. OkHttp(Square)
    • 不基于HttpClient和HttpURLConnection,本身可以理解为一个封装之后的HttpURLConnection
    • 集各种优点与一身
    • Android4.4源码可以看到HttpURLConnection已经替换为OkHttp实现,可见其强大
    1. Retrofit(Square)
    • 基于OkHttp
    • RESTful Api设计风格
    • 通过注解配置请求
    • 支持同步、异步
    • 易与其他框架配合使用,如Rxjava
    • 使用方法较多,原理比较复杂,存在一定的门槛
    • 高度解耦,扩展性极好,堪称代码设计的典范

    总结

    相信看到这里,各位同学对OkHttp有了一个深刻的认识,再结合Retrofit那篇文章看,就更能前后贯通理解整个Retrofit+OkHttp的流程。

    相关文章

      网友评论

          本文标题:OkHttp源码解析

          本文链接:https://www.haomeiwen.com/subject/nhrcqqtx.html