我们创建OkHttpClient客户端的方式通常有两种:
方式一、OkHttpClient client = new OkHttpClient();
// 直接调用 OkHttpClient 的内部类 Builder 的build方法创建;
方式二、OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// 调用 OkHttpClient 的 newBuilder() 方法创建的 Builder对象的 build方法创建。
// newBuilder()方法内部调用的是 Builder对象的构造方法。
方式三、OkHttpClient okHttpClient = new OkHttpClient().newBuilder().build();
上面三者都是创建一个OkHttpClient客户端,其实打开new OkHttpClient()源码我们可以发现,其实OkHttpClient的构造方法里面就是返回一个Builder对象:
public OkHttpClient() {
this(new Builder());
}
不同的是方式一创建的OkHttpClient客户端不能添加拦截器、超时参数、log日志、头文件、缓存等属性,因为OkHttpClient内部没有提供添加这些配置的方法,这些配置都是在OkHttpClient内部的静态内部类Builder中实现的。对于方式二和三,我们进入到OKHttpClient源码,可以发现Builder是它的一个静态的内部类,通过new OkHttpClient.Builder() 或者 new OkHttpClient().newBuilder() 我们就可以获取到builder对象,然后Builder静态内部类里面有一个build()方法,他的源码如下:
public OkHttpClient build() {
return new OkHttpClient(this);
}
不难发现,其实方式二就是我们先初始化Builder对象,方便我们后面设置各种请求场景的参数,然后再调用OkHttpClient的带Builder对象的有参构造方法返回一个OkHttpClient客户端。我们点开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;
}
Builder 构造方法的第一行的Dispatcher对象在整个OKHttp中都是出于一个最核心的超然地位。毕竟再具体的网络请求实现过程中,会遇到各种需求,情况是十分的复杂,而恰好,Builder完美的具备了我们的需求特性。
而Dispatcher,是一个分发器,接收我们发出的同步或者异步请求队列,然后根据我们所设置的条件进行同步或者异步 请求的分发,具体的作用,我们后面做详细的说明。
至此,我们大致知道了OkHttpClient客户端的创建方式以及不同。
然后我们再来看看另一个关键的对象:Request,它主要是帮助我们初始化一个常用的数据请求要用到的一些参数,比如指定URL网络连接地址,请求方法如get、post等。它还可以添加请求头addHeader等等。他的创建方式如下:
// 这里不能像创建OkHttpClient 对象的方式三 那样用 new Request().newBuilder()....来创建,
// 因为 Request 的构造方法不是public类型的。但是 newBuilder() 方法是public类型的。
Request request = new Request.Builder().addHeader(key, value).build();
然后,我们再来看看OKHttp请求还需要用到的另一个参数Call:
Call call = client.newCall(mRequest);
Call对象代表一个实际的一个网络请求,他是OkHttpClient客户端和Request对象的纽带和桥梁,他通过newCall方法把二者串联起来。
最后,Call对象再通过同步或异步方法的调用开始网络请求:
同步请求:call.execute();
异步请求:call.enqueue();
总结起来,OKHttp的使用一共分4个步骤:
1、创建OkHttpClient客户端;
2、创建Request对象;
3、创建Call对象,并通过newCall方法把OkHttpClient客户端和Request对象串联起来
4、调用Call的同步或者异步方法发起网络请求:call.execute()、call.enqueue()。
这里的第一步和第二步都用到了Builder建造者模式。
这里需要注意两点:
一是Call是一个接口,具体的方法有他的实现类RealCall来实现。
二是Call发起同步请求:call.execute()后,系统就处于阻塞状态,直到收到响应结果为止(无论结果是成功还是失败),这时候我们不能做其他的任何操作。Call 发起异步请求:call.enqueue()后,系统会开启一个子线程进行网络请求,系统不会被阻塞,我们该干嘛干嘛,想干嘛干嘛。所以Android开发中,我们都是使用异步请求,否则后果不堪设想。
OkHttp用到的设计模式:
单例模式
Builder 建造者模式
工厂模式(Call.Factory)
责任链模式:链式调用、灵活的解耦
策略模式:请求头包含 "If-Modified-Since" 或 "If-None-Match" 暂时不走缓存;
指定了无缓存,不走缓存;
指定了缓存,则看缓存过期时间,符合要求走缓存