Okhttp源码分析--基本使用流程分析
一、 使用
同步请求
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder()
.get()
.url("www.baidu.com")
.build();
Call call =okHttpClient.newCall(request).execute();
异步请求
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder()
.get()
.url("www.baidu.com")
.build();
Call call=okHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Call call, IOException e) {
Log.i(TAG, "onFailure: ");
}
@Override public void onResponse(Call call, Response response) throws IOException {
Log.i(TAG, "onResponse: ");
}
});
可以看出不管是同步还是异步请求,使用okhttp大致分为3个步骤:
1. 创建okhttpclient
2. 创建请求的request
3. 通过client拿到call、发送请求
注:okhttpclient和request的创建均可采用构造者模式,在构造过程中可根据自己的实际需求设置相应的参数,如可在okhttpclient构造时添加自定义拦截器,在request构造过程中设置连接超时时间等。
二、 源码分析
首先看下OkhttpClient这个类,使用步骤的第一步就是构造OkhttpClient对象。
先贴下官方对OkhttpClient的定义
*Factory for {@linkplain Call calls}, which can be used to send HTTP requests and read their
* responses.
* OkHttpClients should be shared
* OkHttp performs best when you create a single {@code OkHttpClient} instance and reuse it for
* all of your HTTP calls. This is because each client holds its own connection pool and thread
* pools. Reusing connections and threads reduces latency and saves memory. Conversely, creating a
* client for each request wastes resources on idle pools.
OkhttpClient是用于发送请求和读取响应的,官方建议创建一个单例的OkHttpClient,并且所有的http请求都复用它。因为每个OkHttpClient都有自己的connection pool and thread pool。复用connection pool and thread pool可以节约内存,相反如果为每个请求都创建一个OkHttpClient那么会浪费idle pools中的资源。
创建OkHttpClient有两种方式:
1、通过构造函数
2、通过Builder()创建一个client并自定义设置
同时还提供了一个newBuilder()来自定义client,它跟共享的client拥有相同的connection pool, thread pools, and configuration。我们可以用该方法来获取特定设置的client。
OkHttpClient提供无参构造函数,由代码可知它在内部调用OkHttpClient的有参构造函数
,在有参构造函数里对OkHttpClient主要属性做了初始化赋值。
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.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
...//省略N行
}
下面贴下OkHttpClient主要的属性
public class OkHttpClient{
final Dispatcher dispatcher;//分发器
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//协议
final List<ConnectionSpec> connectionSpecs;//传输层版本和连接协议
final List<Interceptor> interceptors;//拦截器 (okhttp核心机制)
final List<Interceptor> networkInterceptors;//网络拦截器
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;//代理选择器
final CookieJar cookieJar;//cookie
final @Nullable
Cache cache;//cache 缓存
final @Nullable
InternalCache internalCache;//内部缓存
final SocketFactory socketFactory;//socket 工厂
final @Nullable
SSLSocketFactory sslSocketFactory;//安全套层socket工厂 用于https
final @Nullable
CertificateChainCleaner certificateChainCleaner;//验证确认响应书,适用HTTPS 请求连接的主机名
final HostnameVerifier hostnameVerifier;//主机名字确认
final CertificatePinner certificatePinner;//证书链
final Authenticator proxyAuthenticator;//代理身份验证
final Authenticator authenticator;//本地省份验证
final ConnectionPool connectionPool;//链接池 复用连接
final Dns dns; //域名
final boolean followSslRedirects;//安全套接层重定向
final boolean followRedirects;//本地重定向
final boolean retryOnConnectionFailure;//连接失败是否重试
final int connectTimeout;//连接超时时间
final int readTimeout;//读取超时时间
final int writeTimeout;//写入超时时间
}
通过浏览源码我们可以发现OkHttpClient采用了构造者设计模式,这样简化参数设置,降低使用成本。比如我们前面简单使用的例子
OkHttpClient类还有一个需要了解的函数就是newCall,因为OkHttpClient实现Call.Factory接口所以覆写了newCall方法,在方法内部返回的是一个RealCall实例。
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
OkHttpClient构造好了之后接下来就是创建request,request就是我们要发送的请求。它也是通过builder模式构造的。下面贴下Request的主要属性以及其构造函数。
public final class Request {
final HttpUrl url;//请求url地址
final String method;//请求方式
final Headers headers;//请求头
final @Nullable RequestBody body;//请求body
final Map<Class<?>, Object> tags;//请求ta