一、okhttp简介

OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。现在在Android开发中最火的应用最多的联网框架毫无疑问是okhttp,目前已经大量替代了Volley、HttpUrlConnection。

二、okhttp用法
1)导包:

    compile 'com.squareup.okhttp3:okhttp:3.9.1'

2)通过Builder类实例化客户端类OkhttpClient。

 private val client: OkHttpClient by lazy {        OkHttpClient.Builder()            .connectTimeout(30, TimeUnit.SECONDS)            .readTimeout(60, TimeUnit.SECONDS)            .writeTimeout(60, TimeUnit.SECONDS)            .build()    }

实例化OkhttpClient时可以通过Builder类添加一系列客户端参数。
3)通过Builder类实例化请求类Request,通过OkHttpClient的newCall方法执行请求。

 fun get(url: String, callBack: ResponseCallBack) {        var request = Request.Builder()            .url(Api.baseUrl + url)            .build()        client.newCall(request).enqueue(            object : Callback {                override fun onFailure(call: Call, e: IOException) {                    callBack?.onFail(e.toString())                }                override fun onResponse(call: Call, response: Response) {                    callBack?.onSuccess(response.body()!!.string())                }            }        )    }    fun post(url: String, requestParams: RequestParams, callBack: ResponseCallBack) {        var requestBody = FormBody.Builder()        requestParams.forEach {            requestBody.add(it.key, it.value.toString())        }        var request = Request.Builder()            .url(Api.baseUrl + url)            .post(requestBody.build())            .build()        client.newCall(request).enqueue(            object : Callback {                override fun onFailure(call: Call, e: IOException) {                    callBack?.onFail(e.toString())                }                override fun onResponse(call: Call, response: Response) {                    callBack?.onSuccess(response.body()!!.string())                }            }        )    }

实例化Request时可以通过Builder类添加一系列请求参数(例如Header信息),这里也不进行详细描述,在分析源码时进行具体分析。
4)同步、异步请求。execute()执行同步请求,enqueue()执行异步请求,同步请求方法返回Response,异步请求通过CallBack返回Response。

三、源码分析
1)OkHttpClient客户端类,主要看一下各个成员变量。

final Dispatcher dispatcher;//请求分发器,分发执行Request  final @Nullable Proxy proxy;//代理  final List protocols;//协议,管理协议版本  final List connectionSpecs;//传输层版本和连接协议  final List interceptors;//拦截器  final List networkInterceptors;//网络拦截器  final EventListener.Factory eventListenerFactory;//请求监听器  final ProxySelector proxySelector;//代理选择  final CookieJar cookieJar;//cookie  final @Nullable Cache cache;//缓存  final @Nullable InternalCache internalCache;//内部缓存  final SocketFactory socketFactory;//socket工厂  final @Nullable SSLSocketFactory sslSocketFactory;//HTTPS ssl安全套接层工厂  final @Nullable CertificateChainCleaner certificateChainCleaner;//验证证书  final HostnameVerifier hostnameVerifier;//确认主机名  final CertificatePinner certificatePinner;//证书链  final Authenticator proxyAuthenticator;//代理身份验证  final Authenticator authenticator;//本地身份验证  final ConnectionPool connectionPool;//连接池  final Dns dns;//DNS域名解析  final boolean followSslRedirects;//安全套接层重定向  final boolean followRedirects;//本地重定向  final boolean retryOnConnectionFailure;//连接失败重试  final int connectTimeout;//连接超时  final int readTimeout;//读取超时  final int writeTimeout;//写入超时  final int pingInterval;//ping命令时间间隔

可以看到所有成员变量都是final的,这样所有的变量赋值就全部交给Builder类,Builder类是OkHttpClient的静态内部类。可以通过builder()来完成设置,在不进行设置情况下会使用Builder的默认设置。

  public Builder() {      dispatcher = new Dispatcher();      protocols = DEFAULT_PROTOCOLS;      connectionSpecs = DEFAULT_CONNECTION_SPECS;      eventListenerFactory = EventListener.factory(EventListener.NONE);      proxySelector = ProxySelector.getDefault();      cookieJar = CookieJar.NO_COOKIES;      socketFactory = SocketFactory.getDefault();      hostnameVerifier = OkHostnameVerifier.INSTANCE;      certificatePinner = CertificatePinner.DEFAULT;      proxyAuthenticator = Authenticator.NONE;      authenticator = Authenticator.NONE;      connectionPool = new ConnectionPool();      dns = Dns.SYSTEM;      followSslRedirects = true;      followRedirects = true;      retryOnConnectionFailure = true;      connectTimeout = 10_000;      readTimeout = 10_000;      writeTimeout = 10_000;      pingInterval = 0;    }

2)Request请求信息类。成员变量如下:

  final HttpUrl url;//请求url信息  final String method;//请求方式(post get)  final Headers headers;//请求header  final @Nullable RequestBody body;//请求Body  final Object tag;//请求tag

3)执行newCall()方法创建Call对象,Call接口唯一实现类是RealCall,是执行请求的真正对象。

  @Override public Call newCall(Request request) {    return RealCall.newRealCall(this, request, false /* for web socket */);  }
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    // Safely publish the Call instance to the EventListener.    RealCall call = new RealCall(client, originalRequest, forWebSocket);    call.eventListener = client.eventListenerFactory().create(call);    return call;  }

RealCall请求类的源码如下:

final class RealCall implements Call {  final OkHttpClient client;  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;//请求重定向拦截器  private EventListener eventListener;  final Request originalRequest;//request信息  final boolean forWebSocket;  // Guarded by this.  private boolean executed;  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    this.client = client;    this.originalRequest = originalRequest;    this.forWebSocket = forWebSocket;    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);  }  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {    // Safely publish the Call instance to the EventListener.    RealCall call = new RealCall(client, originalRequest, forWebSocket);    call.eventListener = client.eventListenerFactory().create(call);    return call;  }  //同步请求  @Override public Response execute() throws IOException {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    eventListener.callStart(this);    try {      client.dispatcher().executed(this);      Response result = getResponseWithInterceptorChain();      if (result == null) throw new IOException("Canceled");      return result;    } catch (IOException e) {      eventListener.callFailed(this, e);      throw e;    } finally {      client.dispatcher().finished(this);    }  }.....//异步请求  @Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    eventListener.callStart(this);    client.dispatcher().enqueue(new AsyncCall(responseCallback));  }  @Override public void cancel() {    retryAndFollowUpInterceptor.cancel();  }  @Override public synchronized boolean isExecuted() {    return executed;  }  @Override public boolean isCanceled() {    return retryAndFollowUpInterceptor.isCanceled();  }  @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.  @Override public RealCall clone() {    return RealCall.newRealCall(client, originalRequest, forWebSocket);  }  StreamAllocation streamAllocation() {    return retryAndFollowUpInterceptor.streamAllocation();  }  final class AsyncCall extends NamedRunnable {    private final Callback responseCallback;    AsyncCall(Callback responseCallback) {      super("OkHttp %s", redactedUrl());      this.responseCallback = responseCallback;    }    String host() {      return originalRequest.url().host();    }    Request request() {      return originalRequest;    }    RealCall get() {      return RealCall.this;    }    @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 {          eventListener.callFailed(RealCall.this, e);          responseCallback.onFailure(RealCall.this, e);        }      } finally {        client.dispatcher().finished(this);      }    }  }//链式请求方法  Response getResponseWithInterceptorChain() throws IOException {    // Build a full stack of interceptors.    List 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, this, eventListener, client.connectTimeoutMillis(),        client.readTimeoutMillis(), client.writeTimeoutMillis());    return chain.proceed(originalRequest);  }

先来分析同步请求,从源码中可以看到同步请求中会先通过

client.dispatcher().executed(this);

完成对请求的监听,本质上是将当前请求放入一个队列中,当请求结束之后再移除队列。

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */  private final Deque runningSyncCalls = new ArrayDeque<>();

对于异步请求来说同样会进行请求的监听,唯一的区别在于异步请求是用两个队列完成,一个是等待请求的队列,一个是正在请求的队列。

/** Ready async calls in the order they'll be run. */  private final Deque readyAsyncCalls = new ArrayDeque<>();  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */  private final Deque runningAsyncCalls = new ArrayDeque<>();

最终进行网络请求是通过链式方法getResponseWithInterceptorChain来完成的。这个方法也是网络请求的精髓所在。这个方法里通过获取设置的一系列拦截器来完成网络请求工作,每个拦截器有不同的分工。最后通过构建的拦截器链调用proceed()方法完成网络请求。由于不同的拦截器分别负责网络请求中的不同工作。分析起来内容比较多,这里先不进行具体各个拦截器的源码分析。

4)Dispatcher请求分发器,在okhttp中网络请求分发是通过Dispatcher分发器来维护的,Dispatcher控制着当前网络请求是否执行还是进入等待状态,这里涉及一些网络请求的域名等判断信息。Dispatcher类源码如下:

public final class Dispatcher {  private int maxRequests = 64;//最大请求数  private int maxRequestsPerHost = 5;//最大主机名  private @Nullable Runnable idleCallback;  private @Nullable ExecutorService executorService;//请求线程池,核心线程0,非核心线程最大值Integer.MAX_VALUE  private final Deque readyAsyncCalls = new ArrayDeque<>();//异步等待队列  private final Deque runningAsyncCalls = new ArrayDeque<>();//异步请求队列  private final Deque runningSyncCalls = new ArrayDeque<>();//同步请求队列.......  public synchronized ExecutorService executorService() {    if (executorService == null) {      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));    }    return executorService;  }  public synchronized void setMaxRequests(int maxRequests) {    if (maxRequests < 1) {      throw new IllegalArgumentException("max < 1: " + maxRequests);    }    this.maxRequests = maxRequests;    promoteCalls();  }  public synchronized int getMaxRequests() {    return maxRequests;  }  public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {    if (maxRequestsPerHost < 1) {      throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);    }    this.maxRequestsPerHost = maxRequestsPerHost;    promoteCalls();  }  public synchronized int getMaxRequestsPerHost() {    return maxRequestsPerHost;  }  synchronized void enqueue(AsyncCall call) {    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {      runningAsyncCalls.add(call);      executorService().execute(call);    } else {      readyAsyncCalls.add(call);    }  }  private void promoteCalls() {    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {      AsyncCall call = i.next();      if (runningCallsForHost(call) < maxRequestsPerHost) {        i.remove();        runningAsyncCalls.add(call);        executorService().execute(call);      }      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.    }  }  private int runningCallsForHost(AsyncCall call) {    int result = 0;    for (AsyncCall c : runningAsyncCalls) {      if (c.host().equals(call.host())) result++;    }    return result;  }  synchronized void executed(RealCall call) {    runningSyncCalls.add(call);  }  void finished(AsyncCall call) {    finished(runningAsyncCalls, call, true);  }  void finished(RealCall call) {    finished(runningSyncCalls, call, false);  }  private  void finished(Deque 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();    }  }  public synchronized List runningCalls() {    List result = new ArrayList<>();    result.addAll(runningSyncCalls);    for (AsyncCall asyncCall : runningAsyncCalls) {      result.add(asyncCall.get());    }    return Collections.unmodifiableList(result);  }  public synchronized int queuedCallsCount() {    return readyAsyncCalls.size();  }  public synchronized int runningCallsCount() {    return runningAsyncCalls.size() + runningSyncCalls.size();  }}

在同步请求时直接加入同步请求队列中,持有同步请求的请求引用。对于异步请求来讲,会判断当前正在执行的请求是否达到最大请求限制,并且正在执行请求的主机名是否达到个数限制,如果都没有达到限制,则立即通过线程池进行网络请求,否则放入异步等待队列。那么什么时候进行执行等待队列中的请求呢?
在一个网络请求结束之后会调用Dispatcher的finished方法,在finished方法中会调用promoteCalls()方法来判断时候可以执行等待队列中的网络请求。

文中demo代码:https://github.com/24KWYL/okhttp.git

更多相关文章

  1. 关于Android(安卓)5.0 网络图标叹号的解决办法
  2. Android——常用的系统服务
  3. Android(安卓)Volley 源码解析
  4. Android之网络访问(一)android 中对apache httpclient及httpurlc
  5. Java集合 && Android提供的集合
  6. 【Tech-Android-View】Android中可以使用的网络音乐资源(榜单 歌
  7. Android文档学习05_网络1
  8. Android(安卓)AsyncTask两种线程池分析和总结
  9. android Webview加载网络图片

随机推荐

  1. 关于前端学习路线的一些建议(含面试自测题
  2. 关于 Babel 你必须知道的基础知识
  3. 继 GitHub 后微软又收购了 npm
  4. 熔断器 Hystrix 源码解析 —— 命令合并
  5. 【51CTO学员故事】6年拿下8个软考证书
  6. 微服务调用链追踪中心搭建
  7. 4.dockerfile
  8. 数据结构之集合和映射
  9. 打印机不断打印出一张张空白纸——好像跟
  10. 进阶 · 那些你必须搞懂的网络基础