okhttp 源码解析(一)

前言

本篇源码分析介绍的是同步请求和异步请求的执行流程以及调度器的相关知识。如果需要学习拦截器链相关知识的,可以直接跳过本篇直接到下一篇进行学习。

基本使用方法

首先要明确一点,okhttp 使用的是 Builder 模式来进行我们网络请求的各种参数设置的,接下来我们先举个简单的例子来看看 okhttp 的同步请求和异步请求是如何使用的。我们首先来看看同步请求的例子:

同步请求举例

/**
 * 同步请求的简单举例
 */
public static void SyncRequest(){
   
    new Thread(new Runnable() {
   
        @Override
        public void run() {
   
            // 1. 构建 OkHttpClient
            OkHttpClient client = new OkHttpClient.Builder()
                    .readTimeout(8, TimeUnit.SECONDS)
                    .connectTimeout(8, TimeUnit.SECONDS)
                    .build();
            // 2. 构建 Request 对象
            Request request = new Request.Builder()
                    .get()
                    .url("https://www.baidu.com")
                    .build();

            try {
   
                // 3. 通过 newCall 方法创建 Call 对象
                Call call = client.newCall(request);
                //4. 通过调用 call 的 execute 方法执行同步请求
                Response response = call.execute();
                Log.d(TAG, response.body().string());
            }catch (IOException e){
   
                e.printStackTrace();
            }
        }
    }).start();
}

这里我们只简要地进行一个设置,主要是说明使用步骤。

  1. 首先,我们要构造出一个 OkHttpClient 对象,它可以说是我们整个流程的一个核心,我们通过 Builder 模式对它进行参数设置,如读写超时、连接超时时间和缓存设置等,这里我只简单地对读超时和连接超时进行了设置。
  2. 其次,我们需要构造出 Request 对象,它用于设置我们的请求参数,同样它也是通过 Builder 模式进行创建的。
  3. 构建完 Request 对象后,我们就可以调用 OkHttpClientnewCall 方法,这个方法会将 Request 对象封装成一个 Call 类型的对象。
  4. 最后就是通过调用 Callexecute 方法来执行同步请求了,我们这里通过一个 Response 类型的变量来接收请求得到的数据。

在这里我们需要注意一点的是,我们的同步请求是放在子线程中去执行的,具体原因很简单:同步请求在没有得到响应的时候,会阻塞线程,而我们的主线程是不允许有耗时操作的,所以我们在这里需要开辟一个子线程来执行这个耗时操作。

讲完了同步请求的流程步骤,接下来我们来看看异步请求的例子。

异步请求举例

/**
 * 异步请求的简单举例
 */
public static void AsyncRequest(){
   
    // 1. 构建 OkHttpClient
    OkHttpClient client = new OkHttpClient.Builder()
            .readTimeout(8, TimeUnit.SECONDS)
            .connectTimeout(8, TimeUnit.SECONDS)
            .build();
    // 2. 构建 Request 对象
    final Request request = new Request.Builder()
            .get()
            .url("https://www.baidu.com")
            .build();
    // 3. 通过 newCall 方法创建 Call 对象
    Call call = client.newCall(request);
    // 4. 通过调用 call 的 enqueue 方法执行异步请求
    call.enqueue(new Callback() {
   
        @Override
        public void onFailure(Call call, IOException e) {
   
            Log.d(TAG, e.getMessage());
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
   
            Log.d(TAG, response.body().string());
        }
    });
}

可以看到,异步请求和同步请求的设置其实有非常多的相似之处,它们的唯一不同点在于第4步的调用方法上,同步方法调用的是 execute,而异步调用的则是 enqueue 方法。enqueue 方法会接收一个 Callback 对象,这个对象会回调两个关键方法:onFailureonResponseonFailure 会在我们请求失败的时候进行回调,而 onResponse 方法则是在得到响应后进行回调。

这里同样需要注意一点,所谓的异步,也就是不会阻塞我们的线程的意思,所以它实际上是在内部自己开辟了一个子线程来接收回调方法的,所以我们的 onFaliure 方法和 onResponse 方法都是位于我们的子线程中,在我们需要执行 UI 的相关操作时,应当先在方法内部切换回主线程进行操作

接下来我们通过一张图来对同步和异步的使用做一个简单的总结:

说完了 okhttp 两种基本的使用方法,接下来我们便要从执行流程来一步步分析 okhttp 的源码了。

源码分析

本着先易后难的原则,笔者会首先对同步请求的执行流程进行分析,然后再对异步请求的执行流程进行分析,由于 okhttp 的源码中涉及的重点如调度器器和拦截器等都是非常大的一块知识,所以笔者会将执行的流程顺序进行梳理,然后在梳理完毕之后再介绍调度器器和拦截器等的知识点。接下来我们来看看同步请求的执行流程。

同步请求的执行流程

通过上面的讲解,我们知道了,在同步请求的时候,我们首先会通过 OkHttpClient.Builder() 来对 OkhttpClient 对象进行构造,我们首先来看看 Builder 里面是什么:

  public Builder() {
   
    dispatcher = new Dispatcher();   // 调度器
    protocols = DEFAULT_PROTOCOLS;
    connectionSpecs = DEFAULT_CONNECTION_SPECS;
    eventListenerFactory = EventListener.factory(EventListener.NONE);
    proxySelector = ProxySelector.getDefault();
    cookieJar = CookieJar.NO_COOKIES;
    socketFactory = SocketFactory.getDefault();
    hostnameVerifier = OkHostnameVerifier.INSTANCE;
    certificatePinner = CertificatePinner.DEFAULT;
    proxyAuthenticator = Authenticator.NONE;
    authenticator = Authenticator.NONE;
    connectionPool = new ConnectionPool();  // 连接池
    dns = Dns.SYSTEM;
    followSslRedirects = true;
    followRedirects = true;
    retryOnConnectionFailure = true;
    connectTimeout = 10_000;  // 连接超时时间
    readTimeout = 10_000;     // 读超时时间
    writeTimeout = 10_000;    // 写超时时间
    pingInterval = 0;
  }

BuilderOkHttpClient 的一个静态内部类,可以看到它的构造方法初始化了非常非常多的成员变量,我们可以通过调用相应的方法来设置这些成员变量的值。然后通过调用 build 方法,就可以返回一个构造完毕的 OkHttpClient 的对象了,build 的源码如下所示:

public OkHttpClient build() {
   
      return new OkHttpClient(this);
}

由于这个方法是 Builder 类中的方法,所以 this 所指的毫无疑问就是我们构造好的 Builder 对象了,通过传入这个构造好的对象,我们就可以构造出我们所需的 OkhttpClient 对象了。

好了,在了解完 OkHttpClient 对象是如何构造出来之后,第二步就是构造 Request 对象了,它也是使用的 Builder 模式构建对象的,所以我们也来看看它的 Builder 里面有什么:

public Builder() {
   
      this.method = "GET";
      this.headers = new Headers.Builder();
}

可以看到在它的内部的 Builder 构造方法中,默认的请求方法是 get 请求,然后还会新建一个请求头。最后也是通过 build 方法构造出我们需要的 Request 对象。

构造完 Request 对象后,接下来就到了我们的第三部,将 Request 对象封装成 Call 对象。它是通过调用 OkHttpClientnewCall 方法实现的,我们来看看这个方法里面做了什么:

 /**
  * Prepares the {@code request} to be executed at some point in the future.
  */
 @Override public Call newCall(Request request) {
   
   return RealCall.newRealCall(this, request, false /* for web socket */);
 }

在这里我们可以看到,这个方法返回的是 RealCallnewRealCall 方法,在这里需要先说明,Call 是一个接口,它的实现类就是 RealCall,我们接下来来看看 RealCallnewRealCall 方法做了什么吧!

static RealCall 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值