上一篇我分析了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. 同步方法拿到返回的结果后直接返回,而异步请求获取到结果后并不直接返回,而是将结果作为参数回调接口的方法去使用的。
新闻热点
疑难解答