OkHttp的实现原理(二)之异步

来源:互联网 发布:兄弟连php怎么样 编辑:程序博客网 时间:2024/06/07 20:42

上一篇我分析了OkHttp采用同步请求的实现原理,这一篇我将继续分析它的第二种请求方式——异步请求,由于这是基于上一篇文章的内容之上的,所以在看这篇文章之前请先浏览上一篇文章http://blog.csdn.net/kbqf24/article/details/56839535。

所谓异步,就是我们不需要坐着等待它出结果,当它有了结果后会回调相应的方法。

让我们来看看OKHttp的异步请求是如何实现的:

public void enqueue(Callback responseCallback) {        this.enqueue(responseCallback, false);    }

我们要传一个Callback接口对象进去,

 void enqueue(Callback responseCallback, boolean forWebSocket) {        synchronized(this) {            if(this.executed) {                throw new IllegalStateException("Already Executed");            }            this.executed = true;        }        this.client.getDispatcher().enqueue(new Call.AsyncCall(responseCallback, forWebSocket, null));    }

首先还是要获得一个分发器,这点跟同步请求是一模一样的,接着往下看

synchronized void enqueue(AsyncCall call) {        if(this.runningCalls.size() < this.maxRequests && this.runningCallsForHost(call) < this.maxRequestsPerHost) {            this.runningCalls.add(call);            this.getExecutorService().execute(call);        } else {            this.readyCalls.add(call);        }    }

原来进行异步请求是有门槛限制的,它要求总的异步请求的数量小于maxRequests =64,并且对于一个主机来说最多同时发出5个请求,如果没有满足这个条件,那么就将这个call对象加入到readyCalls数组中以备日后使用,这个数组相当于是一个缓冲数组,如果满足了这个条件,那么就将AsyncCall这个对象添加到runningCalls数组当中,并且使用线程池来执行这个任务,那么这个AsyncCall到底是什么了?它是Call的一个内部类并且实现了Runnable接口,那么走 this.getExecutorService().execute(call);这个方法当然就是要去执行call里面的run()方法啊,我们来看看这个方法:

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

这个方法会去执行execute(),并且会在执行期间给每个任务所在的线程取不同的名字。

 protected void execute() {            boolean signalledCallback = false;            try {                Response e = Call.this.getResponseWithInterceptorChain(this.forWebSocket);                if(Call.this.canceled) {                    signalledCallback = true;                    this.responseCallback.onFailure(Call.this.originalRequest, new IOException("Canceled"));                } else {                    signalledCallback = true;                    this.responseCallback.onResponse(e);                }            } catch (IOException var7) {                if(signalledCallback) {                    Internal.logger.log(Level.INFO, "Callback failure for " + Call.this.toLoggableString(), var7);                } else {                    Request request = Call.this.engine == null?Call.this.originalRequest:Call.this.engine.getRequest();                    this.responseCallback.onFailure(request, var7);                }            } finally {                Call.this.client.getDispatcher().finished(this);            }        }
Response e = Call.this.getResponseWithInterceptorChain(this.forWebSocket);

这个方法是不是也很熟悉啊,跟同步获取数据的方法是一摸一样的,一个方法在上一篇文章中详细说明了的,这里就不再展开来说了,然后再判断这个任务是否被cancel掉了,如果是,那么就会调用我们传入的Callback接口对象的onFailure()方法,如果没有被取消,那么就会回调该接口中的onResponse(response)方法。
那么异步请求的代码我们也就分析完了,跟同步请求其实区别并不大,我们来分析一下他们的区别,
1. 同步:将Call对象之间放入分发器Dispatcher中
异步:将AsyncCall对象放入分发器Dispatcher中,
2. 同步方法不会自动给你开线程去调用getResponseWithInterceptorChain(this.forWebSocket)获取数据,所以你必须自己开启线程去执行。
异步方法OkHttp会使用内部的线程池中的线程去执行获取数据(getResponseWithInterceptorChain(this.forWebSocket))的耗时操作,所以你可以在主线程中使用异步请求。
3. 同步方法拿到返回的结果后直接返回,而异步请求获取到结果后并不直接返回,而是将结果作为参数回调接口的方法去使用的。

0 0