okHttp网络请求

一,异步OkHttp请求示例

private void testOkHttp() throws IOException {
        final OkHttpClient client = new OkHttpClient();
        final Request request = new Request.Builder().url("https://www.google.com.hk").build();

        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                    Log.i(TAG,response.toString());
                    Log.i(TAG,response.body().string());
            }
        });
    }

上面的代码就实现了一个网络请求. 创建一个OkHttpClient对象,他包含了分发器,连接池,拦截器等等内容. 接下来创建一个请求对象,通过OkHttpClient的newCall()方法对其包装,然后添加请求队列,然后回调结果

Tip
对于OkHttpClient封装一个单实例,让所有的Http请求都重用它, OkHttp将会有更好的性能.因为每一个OkHttpClient实例都持有自己的连接池,线程池等,重用连接池和线程池能够减少网络访问延迟以及节省内存,减少资源的浪费

下面我们就详细的分析一下OkHttp详细的网络访问流程

二,OkHttp详访流程

1,创建HttpClient对象.

public OkHttpClient() {
    this(new Builder());
  }

  OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    ... ...
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;
  }

由上面可知HttpClient创建的时候,初始化了连接池,线程池,默认拦截器等等,为接下来的网络请求铺垫

2,创建Request对象
1)

Request request = new Request.Builder().url("https://www.google.com.hk").build();

通过Request中的Builder构建一个请求对象
这个Request对象我们可以理解成一个请求Bean,里面封装了请求的url, 请求方法(post get put delete等),请求头,请求体,以及tag(用于批量取消)

 public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

接下来继续对Request对象进行包装,使其能够执行execute,入队enqueue, 取消cancel, 判断状态 isCancel和isExecuted
上面的call指向的是RealCall对象
我们看下Call接口

public interface Call extends Cloneable {
  Request request();
  Response execute() throws IOException;
  void enqueue(Callback responseCallback);
  void cancel();
  boolean isExecuted();
  boolean isCanceled();
  Call clone();
  interface Factory {
    Call newCall(Request request);
  }
}

3,将请求入队

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

OkHttpClient的dispatcher()方法返回的是一个Dispatcher对象,每个Dispatcher使用线程池来运行上面的Call任务.

接下来我们看下Dispacher的入队操作

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

runningAsyncCalls存放所有正在执行的异步任务
readyAsyncCalls存放所有正在等待执行的异步任务
当正在执行的请求小于最大请求数64且每个主机的最大请求数不超过5 则直接加入到正在执行的异步队列中且执行.
否则加入到正在等待执行的异步队列中等待执行.

由上我们可知
请求相同主机的最大请求数目是5
所有请求最大数目是64
实际开发中,用户量一般的app服务器只有一个,那么一般最大的请求就是5 

好了,一个请求封装准备了这么多, 顺利入队,下面我们看看他下面是怎么执行的

4,执行
RealCall封装了原始的Request,在RealCall中有一个非静态内部类AsyncCall,AsyncCall中的execute方法就是任务要执行的代码

final class AsyncCall extends NamedRunnable {
   ... ...
   ... ...
    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

通过getResponseWithInterceptorChain方法 获取到Response对象,下面我们看下他的拦截链

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

RealInterceptorChain.java
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      Connection connection) throws IOException {
   ... ...
    //取出下一个拦截器,递归调用
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
  ... ...
    return response;
  }

1)首先添加用户自定义的拦截器(如果有),接着依次添加重试拦截器,桥接拦截器,缓存拦截器,连接拦截器以及访问服务器的拦截器.
这些拦截器的添加顺序是固定的,不能改变
2)这些拦截器形成一个拦截链,每个拦截器专司其自己的职责, 将处理好的请求交给下一个拦截器,最后一个拦截器处理完毕后,再将其交给上一个拦截器,直到第一个, 最后将结果返回.这样一个责任链就形成了
3)每个拦截器都实现Interceptor接口

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}

4)对于拦截器之间的调用过程可能不太容易理解,下面针对2)给出一个示意图
Req: 请求Request缩写
Res: 响应Response缩写


基本流程图.png

5,结果回调
我们再将目光回到AsyncCall类

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

当通过getResponseWithInterceptorChain()一系列的处理得到结果后.
1),会首先判断结果是否取消, 如果取消则回调传入的回调onFail中
否则,回调结果到onResponse中
2),接下来是扫尾操作
调用Dispatcher的finish方法

void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  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) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

它主要做了两件事儿
A,将刚才已经完成的任务从runningAsyncCalls移除
B,如果runningAsyncCall小于5(每个主机的最大访问数量), 则从readyAsyncCalls移除添加到runningAsyncCalls中,并且执行

至此一个完整的OkHttp异步请求完毕
总的来说: 就是根据请求的url, 请求方法, 请求体构造一个Request的Bean, 然后将Request封装成一个RealCall,RealCall实现了Call接口,他有对执行逻辑的操作(取消,执行,判断执行的状态等), 接下来通过全局的OkHttpClient(拥有线程池,连接池,分发器等资源),利用分发器Dispatcher加入到执行队列或者等待队列中.
然后线程池执行RealCall的非静态内部类AsyncCall的execute方法, 然后通过getResponseWithInterceptorChain来进行一系列的拦截器操作处理,回调请求结果.
最后进行扫尾操作,移除正在执行队列的当前请求,将等待队列的请求添加到执行队列.

OkHttp的处理核心是在拦截器,每个拦截器都有自己的职责,下一篇文章详细分析各个拦截器具体都干了什么

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值