简单使用OkHttp3

阅读本文需要对OkHttp3的使用有一定了解。

首先我们先看看如何简单进行一个get请求的Request。

Request qqRequest = new Request.Builder()                        .url("http://www.qq.com")                        .build();Call call = mOkHttp.newCall(qqRequest);call.execute();//特别注意 这里要在子线程执行

或者可以使用:

Request qqRequest = new Request.Builder()                        .url("http://www.qq.com")                        .build();Call call = mOkHttp.newCall(qqRequest);//使用enquuecall.enqueue(new Callback() {    @Override    public void onFailure(Call call, IOException e) {        e.printStackTrace();    }    @Override    public void onResponse(Call call, Response response) throws IOException {        Log.i(TAG, response.body().string());    }});

execute执行流程源代码分析

要看execute就要先看

Call call = mOkHttp.newCall(qqRequest);

点进去源代码我们发现 返回了一个RealCall对象,因为Call是一个接口,而RealCall才是真正的实现类

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

现在我们找到execute方法的源代码:

  @Override   public Response execute() throws IOException {    synchronized (this) {//同步锁,为了防止子线程同时调用而导致出现多次网络请求      if (executed) throw new IllegalStateException("Already Executed");      executed = true;//这里表明,对应的Call只能执行一次    }    try {      client.dispatcher().executed(this);//加入到请求队列      Response result = getResponseWithInterceptorChain(false);//核心代码!      if (result == null) throw new IOException("Canceled");      return result;    } finally {      client.dispatcher().finished(this);//从请求队列中移除    }  }

首先 我们看下一不太重点的两行代码:

···client.dispatcher().executed(this);//加入到请求队列···client.dispatcher().finished(this);//从请求队列中移除

这里是用来干嘛的?

1.Dispatcher辅助管理请求

我把相关代码贴出来:

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */  private final Deque runningSyncCalls = new ArrayDeque<>();  /** Used by {@code Call#execute} to signal it is in-flight. */  synchronized void executed(RealCall call) {    runningSyncCalls.add(call);  }  /** Used by {@code Call#execute} to signal completion. */  synchronized void finished(Call call) {    if (!runningSyncCalls.remove(call)) throw new AssertionError("Call wasn't in-flight!");  }  /**   * Cancel all calls currently enqueued or executing. Includes calls executed both {@linkplain   * Call#execute() synchronously} and {@linkplain Call#enqueue asynchronously}.   */  public synchronized void cancelAll() {    for (AsyncCall call : readyAsyncCalls) {      call.cancel();    }    for (AsyncCall call : runningAsyncCalls) {      call.cancel();    }    for (RealCall call : runningSyncCalls) {      call.cancel();    }  }

从上面这段代码可以看出,它是用来将这个请求加入队列中的,方便我们取消任务的。

2.ApplicationInterceptorChain与proceed()

搞懂了之后,我们来看看execute执行的那一行核心代码:

//核心代码!Response result = getResponseWithInterceptorChain(false);

这里调用了getResponseWithInterceptorChain方法(废话,我够知道)- -#。 我们来看看相关代码:

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);    return chain.proceed(originalRequest);  }  class ApplicationInterceptorChain implements Interceptor.Chain {    private final int index;    private final Request request;    private final boolean forWebSocket;    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {      this.index = index;      this.request = request;      this.forWebSocket = forWebSocket;    }    @Override public Connection connection() {      return null;    }    @Override public Request request() {      return request;    }    @Override public Response proceed(Request request) throws IOException {      // If there's another interceptor in the chain, call that.      if (index < client.interceptors().size()) {        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);        Interceptor interceptor = client.interceptors().get(index);        Response interceptedResponse = interceptor.intercept(chain);        if (interceptedResponse == null) {          throw new NullPointerException("application interceptor " + interceptor              + " returned null");        }        return interceptedResponse;      }      // No more interceptors. Do HTTP.      return getResponse(request, forWebSocket);    }  }

getResponseWithInterceptorChain里面创建了一个ApplicationInterceptorChain对象,并且调用了它的proceed方法。

我们来看一下传入的这个参数:0。 实际上这个0是有特殊含义的。

这里面涉及了OkHttp3的新特性:拦截器Interceptor。 它可以添加多个拦截器,而这里的0的意思,就是从第1个拦截器开始。

简单了解完之后,我们看看关键的proceed代码

    @Override     public Response proceed(Request request) throws IOException {      // If there's another interceptor in the chain, call that.      // 判断还有没有拦截器? 有的话先走拦截器      if (index < client.interceptors().size()) {        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);//创建下一个拦截器的chain        Interceptor interceptor = client.interceptors().get(index);//获取拦截器        Response interceptedResponse = interceptor.intercept(chain);//传递过去        //这里要注意,拦截器返回的Response不能为空        if (interceptedResponse == null) {          throw new NullPointerException("application interceptor " + interceptor              + " returned null");        }        //返回结果        return interceptedResponse;      }      // No more interceptors. Do HTTP.      //当执行完拦截器之后,执行真正的Http请求。      return getResponse(request, forWebSocket);    }

相信看完上面的注释,我相信大家也有一定的了解了。

有一个地方需要大家注意的,在官方文档中关于Application Interceptors有一句这样的话:

Permitted to short-circuit and not call Chain.proceed().

意思是,我们可以在拦截器中,不调用proceed()。 但是proceed正是返回我们Response的方法啊!

我不太明白这个设计理念!

就此问题,我专门去OkHttp的Issues提问,有幸获得了JakeWharton大神的回答(没错,那位JakeWharton)
附上链接:
What’s mean “Permitted to short-circuit and not call Chain.proceed().”?

请原谅我的渣英语。(逃

JakeWharton大神是这样说的:

意思是说:这样的设计是用在Http缓存里面的。执行请求之前,我们可以先从本地读取,看看有没有这个请求的缓存。如果没有,我们就调用proceed的方法!

但是需要再次注意,就算我们不调用这个proceed方法,也一定要返回一个Response对象! 这样才可以避免抛出空指针异常。:

        if (interceptedResponse == null) {          throw new NullPointerException("application interceptor " + interceptor              + " returned null");        }

分析完上面之后,我们发现,它调用了:

      // No more interceptors. Do HTTP.      //当执行完拦截器之后,执行真正的Http请求。      return getResponse(request, forWebSocket);

这里才是真正执行Http请求的地方。

关于getResponse具体内容,我就不再继续分析了….因为需要的篇幅比较大,我会在接下来的文章进行分析! 先大概了解是用HttpEngine这个类来进行请求的!

结束

OK!关于execute方法,就分析地差不多了。应该也讲地比较清楚了,请务必搞懂上面的内容,因为enqueue的方法是调用execute的方法的!

所以要是看不懂execute…那enqueue也看不懂了!

下篇文章将带来enqueue的源代码流程分析!(虽然你看懂了execute之后,也可以自己尝试看看enqueue的源代码了!)

备注

关于拦截器,这不属于本文范围,将在后续的文章中进行讲解。
这里也附上一些学习的链接:
官方Wiki Interceptor

官方Wiki Interceptor中文翻译

或者可以看我另外一篇文章(这里是项目中的实际应用,品完官方文档,食用更佳):
【项目重构】使用OkHttp解决Session过期导致用户掉线的问题

-Hans 2016.4.3 21:30

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. Android(安卓)stutdio2.2 启动模拟器出现“/dev/kvm is not foun
  3. Android(安卓)Launcher 详解
  4. 【Android(安卓)开发教程】重写onKeyDown()
  5. 自定义Android的Dialog
  6. 【Android(安卓)百度地图实战】2.几种地图图层的显示
  7. Android(安卓)Accessibility : TalkBack的状态读取
  8. Android(安卓)Java(2015-6-18 15:28、2016-1-30 21:18、2016-5-31
  9. Android中使用Timer配合postInvalidate()刷新View

随机推荐

  1. 简单的 Android 拍照并显示以及获取路径
  2. Android 利用发送Intent播放本地视频和网
  3. Android 动画效果设置
  4. Android Studio初步使用及HelloWorld详解
  5. android 横向滚动屏幕实现(1)
  6. Android(安卓)基于Retrofit+Rxjava搭建的
  7. 我的android 第15天 -使用SQLiteOpenHelp
  8. Android(安卓)4.4 webview 架构
  9. android ndk开发
  10. Android 日历提供器(二)