OKHttp3源码解析(二)异步请求的源码分析

继OKHttp3源码解析(一)同步请求的源码分析

​OkHttpClient okHttpClient = new OkHttpClient.Builder().build();//创建单例
Request request = new Request.Builder()//创建请求
        .url("http://www.baidu.com")
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
     Log.d(TAG,"失败");
}
 
@Override
public void onResponse(Call call, Response response) throws IOException {
      Log.d(TAG,"成功");               
}
});
 
​

与同步请求一样前三步

第一步创建了OKHttpClient

第二步创建Request

第三步需要创建一个Call对象

其实前三步骤并没有进行真正的发起网络请求,只是帮我们做了网络请求前期的操作,其实真正的网络请求是在第四步当中

第四步调用enqueue

public void enqueue(Callback responseCallback) {
        synchronized(this) { //锁住了当前的对象,this指的是RealCall这个对象
            if (this.executed) {//用于表示这个RealCall的这个实例是否执行过,如果执行过了就会抛出异常,表明enqueue只能执行一次
                throw new IllegalStateException("Already Executed");
            }

            this.executed = true;//如果没有执行过,就会设置true
        }

        this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));//①AsyncCall②enqueue
}

①的执行方法

final class AsyncCall extends NamedRunnable {  //继承了Runnable
        private final Callback responseCallback;
		private AsyncCall(Callback responseCallback) {
            super("OkHttp %s", new Object[]{RealCall.this.redactedUrl().toString()});
            this.responseCallback = responseCallback;
        }
}

②的执行方法

private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque();//运行在dispatcher中  判断并发请求的数量
	private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque();//表示缓存等待的请求队列
	private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
	synchronized void enqueue(AsyncCall call) {
        if (this.runningAsyncCalls.size() < this.maxRequests && this.runningCallsForHost(call) < this.maxRequestsPerHost) {
			//判断当前异步请求的数量是否小于最大请求数,以及正在运行的主机的请求是否小于设定的主机请求的最大值
            this.runningAsyncCalls.add(call);//帮当前请求的AsyncCall加到异步队列中
            this.executorService().execute(call);//通过这个线程池去执行这个异步请求
        } else {
            this.readyAsyncCalls.add(call);//如果超出了设定的值,就会放到等待队列当中
        }
}

这个方法的意思是:当你要发起一个异步的网络请求的时候,它首先会判断当前正在请求的Runnale的个数是否小于它的最大值否则就会加入等待的队列当中

总结:首先通过执行call.enqueue()这个方法,第一步会判断是否只执行了一次如果不是的话就会抛出异常,第二步通过传递进来的一个CallBack对象,把它封装成了一个AsyncCall对象,这个对象其实就是Runnable对象第三步构建AsyncCall对象之后,通过dispather调用enqueue方法进行异步的网络请求,同时当前异步请求的数量是否小于64,以及正在运行的主机的请求是否小于设定的5个请求,就会把当前的AsyncCall请求放到请求异步队列当中,如果超出设定的值就会放到等待就绪的异步队列当中

接下来分析一下OKHttp的线程池

public synchronized ExecutorService executorService() {// synchronized锁住了该方法
    if (this.executorService == null) {
        this.executorService = new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }

    return this.executorService;
}

可以从上面方法中看出,当executorService为空的时候才可以创建,不为空的时候就直接return,很明显当前线程池的方法是一个单例。
由于它是个线程池,我们就会调用每个子线程的Run方法,通过执行this.executorService().execute(call);就会调用AynscCall的run方法,接下来看一下AsyncCall是如何做的实现

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    private AsyncCall(Callback responseCallback) {
        super("OkHttp %s", new Object[]{RealCall.this.redactedUrl().toString()});
        this.responseCallback = responseCallback;
    }

    String host() {
        return RealCall.this.originalRequest.url().host();
    }

    Request request() {
        return RealCall.this.originalRequest;
    }

    RealCall get() {
        return RealCall.this;
    }

    protected void execute() {
        boolean signalledCallback = false;

        try {
            Response response = RealCall.this.getResponseWithInterceptorChain();
            if (RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {
                signalledCallback = true;
                this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
            } else {
                signalledCallback = true;
                this.responseCallback.onResponse(RealCall.this, response);
            }
        } catch (IOException var6) {
            if (signalledCallback) {
                Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), var6);
            } else {
                this.responseCallback.onFailure(RealCall.this, var6);
            }
        } finally {
            RealCall.this.client.dispatcher().finished(this);
        }

    }
}

但是这个里面是没有Run方法的,去NamedRunnable看一下

public abstract class NamedRunnable implements Runnable {
    protected final String name;

    public NamedRunnable(String format, Object... args) {
        this.name = Util.format(format, args);
    }

    public final void run() {
        String oldName = Thread.currentThread().getName();
        Thread.currentThread().setName(this.name);

        try {
            this.execute();
        } finally {
            Thread.currentThread().setName(oldName);
        }

    }

    protected abstract void execute();  //抽象的方法
}

原来转了一圈又回去了,其实execute() 就是在Run方法里面,execute方法才是具体的实现

接下来看一下execute方法

protected void execute() {
    boolean signalledCallback = false;

    try {
        Response response = RealCall.this.getResponseWithInterceptorChain();//在同步方法中也执行了这个方法,这个拦截链后续会详细的详解,这个其实就是构建拦截器的链,而每一个拦截器链中的拦截器是不同作用的通过这个方法会返回Response对象
        if (RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {//来判断这个拦截器链当中的一个拦截器叫做重定向和重试拦截器,这个拦截器是否取消了
            signalledCallback = true;
            this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));//如果取消了就会调用onFailure方法
        } else {
            signalledCallback = true;
            this.responseCallback.onResponse(RealCall.this, response);//如果没有被取消就辉调用onResponse这个回调方法,这里是做网络请求操作的
        }
    } catch (IOException var6) {
        if (signalledCallback) {
            Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), var6);
        } else {
            this.responseCallback.onFailure(RealCall.this, var6);
        }
    } finally {
        RealCall.this.client.dispatcher().finished(this);//③主动回收异步请求
    }

}

由此方法可知,不管是onFailure还是onResponse都是在子线程里面做的,所以如果要做一些UI显示一定要在主线程里来做

③的执行方法

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized(this) {
        if (!calls.remove(call)) {  //把这个放到异步队列中的请求删除
            throw new AssertionError("Call wasn't in-flight!");
        }

        if (promoteCalls) {
            this.promoteCalls();//调整我们整个异步请求任务队列
        }

        runningCallsCount = this.runningCallsCount();//重新计算正在执行的线程数量然后赋值
        idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {//如果当前线程数量为0的话而且当前的callback不为空的情况下执行run
        idleCallback.run();
    }

}

总结:第一步创建一个OKHttpClient对象,这个是OKHttp请求的客户端类,第二步构建一个Request对象,通过它的bulider模式创建它的url参数头部信息等等,通过OKHttpClient和Request对象,构建出实际的OKhttp请求Call对象,最后执行call的enqueue方法,把整个OKHttp请求放到调度器当中,由于是异步的给他注入CallBack对象以便用来网络请求的分发过程。下一篇会详细的介绍dispatcher分发器

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万子开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值