这个库一直想要去学习,不过一直没有时间去做,打算一点点梳理Okhttp。本文将按照发起网络请求的顺序来详细描述下okhttp是如何发起网络请求的,其中包含一些优秀文章可供大家参考。
文章目录
使用实例
先放一段Okhttp的使用代码。
//1
OkHttpClient client=new OkHttpClient();
//2
Request request = new Request.Builder()
.url("url)
.build();
//3
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String results = response.body().string();
}
});
我们阅读源码就要从暴露给用户使用的那个类先去入手,对应Okhttp就是**(创建)OkhttpClient**,以及Request,Callback,在新写Callback的时候要重写onFailure(Call call, IOException e)与OnResponse(Call call, Response response)两个函数,于是另一个重要的类Response类简单来说,使用的时候,只需要传入网络的url地址,然后加上新创建的Callback对象(包括重写两个函数)就完成了对url地址的访问(获取数据或上传数据)。
整体流程
1.创建OkhttpClient实例
在读源码之前,每个类都会有一些注释,先阅读下注释。
1.1 用户使用时,创建全局(单例)实例
这里的意思就是说,最好在整个应用中只包含一个(全局)OkhttpClient实例,在每一个发起Http请求的时候重用该实例即可(单例),同时复用的还有Response缓存、共用线程池以及共用连接池。
* <h3>OkHttpClients should be shared</h3>
*
* <p>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.
1.2 构造方式
可以使用两种方式创建OkHttpClient的实例(构造函数和使用Builder),以及一种特殊的构造方式。
还是先看注释。
<p>Use {
@code new OkHttpClient()} to create a shared instance with the default settings:
* <pre> {
@code
*
* // The singleton HTTP client.
* public final OkHttpClient client = new OkHttpClient();
* }</pre>
*
* <p>Or use {
@code new OkHttpClient.Builder()} to create a shared instance with custom settings:
* <pre> {
@code
*
* // The singleton HTTP client.
* public final OkHttpClient client = new OkHttpClient.Builder()
* .addInterceptor(new HttpLoggingInterceptor())
* .cache(new Cache(cacheDir, cacheSize))
* .build();
* }</pre>
我们来读源码。
这是第一种默认的方式
public OkHttpClient() {
this(new Builder());
}
最后会调用该函数,使用的就是默认的Builder
private OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
...
}
第二种方式:想要配置OkhttpClient的一些参数,就需要使用Builder。
public final OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor())
.cache(new Cache(cacheDir, cacheSize))
...//其他设置
.build();
最后调用Builder类内的build函数,这里的this就是Builder,所以会调用OkhttpClient(Builder builder)来更改client的数据域。
public OkHttpClient build() {
return new OkHttpClient(this);
}
总结:OkHttpClient本身不能设置参数,需要借助于其内部类Builder设置参数,参数设置完成后,调用Builder的build方法得到一个配置好参数的OkHttpClient对象。这些配置的参数会对该OkHttpClient对象所生成的所有HTTP请求都有影响。
第三种方式:我们先看注释中的文字。
您可以使用{@link#NewBuilder()}自定义共享的OkHttpClient实例。 这将构建一个共享相同连接池,线程池和配置的客户端。 使用生成器方法为特定目的配置派生客户端。
共享相同连接池,线程池和配置的客户端,共享谁的呢?当然是共享那个client实例的。有时候我们想单独给某个网络请求设置特别的几个参数,比如只想设置某个请求的超时时间,但是还想保持OkHttpClient对象(client)中的其他的参数设置,那么可以调用OkHttpClient对象的newBuilder()方法。
* <h3>Customize your client with newBuilder()</h3>
*
* <p>You can customize a shared OkHttpClient instance with {
@link #newBuilder()}. This builds a
* client that shares the same connection pool, thread pools, and configuration. Use the builder
* methods to configure the derived client for a specific purpose.
*
* <p>This example shows a call with a short 500 millisecond timeout: <pre> {
@code
*
* OkHttpClient eagerClient = client.newBuilder()
* .readTimeout(500, TimeUnit.MILLISECONDS)
* .build();
* Response response = eagerClient.newCall(request).execute();
* }</pre>
这里的this是Okhttp的实例
public Builder newBuilder() {
return new Builder(this);
}
之后会调用Builder类中的这个构造函数,这样就在builder中保存了OkHttpClient中的参数。
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
this.connectionSpecs = okHttpClient.connectionSpecs;
...
}
1.3 优点
不需要将其杀掉。
保持空闲的线程和连接将自动释放。
<h3>Shutdown isn't necessary</h3>
1.4 涉及的模式
1.构造者模式
不用说了,都有builder了,肯定就是构造者模式了。
2.单例模式
有点单例模式的意思,但这里没有,就是我们构建的OkhttpCilent最好要单例,只构造一个来复用。
3.外观模式
用户可以使用这个类来进行一些操作来实现内部的功能。
2.构造Request对象
构造方法
Request也是需要通过构造者模式来构造。
private Request(Builder builder