网络框架okHttp源码分析

引言

在上一篇博客中,我们讲解了okHttp网络框架的基本使用,包括get请求,post请求,单个文件上传,多个文件上传,其中最主要的就是各个请求的request的封装。我们来回顾一下,get请求只需要一个url即可,post请求需要一个FormBody,单个文件上传需要拿到File对象,然后封装成一个requestBody,多个文件上传需要添加MutilpartBody和CountingRequestBody。

这一节我们就从源码的角度来解析一下okHttp网络框架中异步请求的实现原理。

源码解析

在我们创建request请求后,我们就会使用client对象来创建一个call对象。我们可以对这个call对象进行同步操作,也可以对其进行异步操作。其中,同步操作对应的是它的execute()方法,异步对应的是enqueue()方法。

接下来我们用代码来演示如何进行异步和同步的操作:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("http://www.baidu.com")
        .build();
Call call = okHttpClient.newCall(request);
//1.异步请求,通过接口回调告知用户 http 的异步执行结果
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        System.out.println(e.getMessage());
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful()) {
            System.out.println(response.body().string());
        }
    }
});
//2.同步请求
//Response response = call.execute();
//if (response.isSuccessful()) {
//    System.out.println(response.body().string());
//}

Call

点开Call的源码,我们可以发现它是一个接口,它的内部定义了一些方法,比如execute()、cancel()。
代码如下:

package okhttp3;

import java.io.IOException;

public interface Call {

  Request request();

  Response execute() throws IOException;

  void enqueue(Callback responseCallback);

  void cancel();

  boolean isExecuted();

  boolean isCanceled();

  interface Factory {
    Call newCall(Request request);
  }
}

所以它负责去执行request请求,但是每一个call只能负责去执行一个请求,所以它的内部实现了Call.Factory接口,让它具备了创建Call对象的功能。

newCall

点开newCall的源码,我们可以发现,它给我们返回一个RealCall对象,这个RealCall就是Call接口的具体实现类。

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

这里写图片描述

enqueue()

接下来在Activity中调用Call.enqueue(Callback)方法,点进去之后代码如下:
这里写图片描述

在enqueue的一参方法中调用了二参的方法,并将第二个参数forWebSocket置为了false。
而在二参方法中,我们会发现它最终调用了client.dispatcher().enqueue()方法,并且将Callback和forWebSocket这两个参数封装到了一个叫做AsyncCall的对象当中。

dispatcher

这个dispatcher就是okHttpClient中的一个全局变量,点进代码如下:

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

可以看到Dispatcher内部是通过一个线程池来执行的,超过最大请求数后就先加入准备请求的队列当中。在if代码块中,会执行 executorService().execute(call);所以这个call对象就是一个Runnable对象。

AsyncCall

点进AsyncCall代码中,我们可以看到它继承了NameRunnable,而NameRunnable又继承了Runnable接口并在run方法中主动调用了execute方法,代码如下:
这里写图片描述

而这个抽象的execute方法在AsyncCall中已经被实现了,如下图所示:
这里写图片描述

由上图可知,当我们执行一个AsyncCall的execute()方法时,会调用一个叫做getResponseWithInterceptorChain的方法,并返回Response对象,然后通过接口回调的方式将Response返回给我们的Activity中所实现的Callback接口并刷新UI。

getResponseWithInterceptorChain()

那么这个方法是怎么干什么的呢,点开源码:
这里写图片描述

在这里,我们首先创建了一个ApplicationInterceptorChain对象,然后调用了它的proceed方法。
这里写图片描述

在proceed方法中,判断如果index小于okHttpClient中拦截器的个数,则会递归创建新的ApplicationInterceptorChain对象,并将这个新的ApplicationInterceptorChain对象传递给index下标的拦截器的intercept()方法。

在这个递归循环中,最终index都会处于>=client.interceptor.size的阶段,因此最后会调用一行代码:

getResponse(request, forWebSocket)

这个方法就是真正发送网络请求并获取Response的方法。

getResponse

这里写图片描述

如图所示,在getResponse方法中创建了一个HttpEngine的对象,然后分别调用HttpEngine的sendRequest和readResponse方法,这两个方法依次是发送网络请求和读取网络请求结果,最后将Response对象返回到之前说的getResponseWithInterceptorChain方法,并回传给Activity中的Callback。

最后,用两个图来做一个总结:
这里写图片描述

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值