OkHttp3使用(二)-常用类介绍

对整个OkHttp框架的介绍,会分为使用篇和源码分析篇两个部分进行介绍:
这里是使用篇的目录:
(一)-基本使用
(二)-常用类介绍
(三)-Interceptor
源码分析篇敬请期待……

上一篇文章中先整体梳理下OkHttp的用法,没有对于其中涉及到的一些类进行介绍,所以这边文章,我们对其中比较重要的几个类进行一些介绍。但是关于这些类的介绍,还是推荐大家去官网api的文档进行查看是最好的,这个才是真正熟悉类最好的方法。
我们知道,OkHttp发起请求的过程如下:

OkHttpClient client = new OkHttpClient();

  String run(String url) throws IOException {
    Request request = new Request.Builder()
        .url(url)
        .build();

    try (Response response = client.newCall(request).execute()) {
      return response.body().string();
    }
  }

我们就根据这个发起请求的过程,来一次介绍其中涉及到的类。

1 OkHttpClient

我们看官方给其的定义就是

Factory for calls, which can be used to send HTTP requests and read their responses.

它的主要目的就是用来创建Call对象的,而这个Call对象是用来发起HTTP请求和读取返回结果的。所以,其就是一个工厂类,里面封装了我们请求的一些配置参数而已。而对于配置的分装,通常我们会使用其内部类Builder进行设置,我们看下Builder类:

public static final class Builder {
    Dispatcher dispatcher;
    @Nullable Proxy proxy;
    List<Protocol> protocols;
    List<ConnectionSpec> connectionSpecs;
    final List<Interceptor> interceptors = new ArrayList<>();
    final List<Interceptor> networkInterceptors = new ArrayList<>();
    EventListener.Factory eventListenerFactory;
    ProxySelector proxySelector;
    CookieJar cookieJar;
    @Nullable Cache cache;
    @Nullable InternalCache internalCache;
    SocketFactory socketFactory;
    @Nullable SSLSocketFactory sslSocketFactory;
    @Nullable CertificateChainCleaner certificateChainCleaner;
    HostnameVerifier hostnameVerifier;
    CertificatePinner certificatePinner;
    Authenticator proxyAuthenticator;
    Authenticator authenticator;
    ConnectionPool connectionPool;
    Dns dns;
    boolean followSslRedirects;
    boolean followRedirects;
    boolean retryOnConnectionFailure;
    int callTimeout;
    int connectTimeout;
    int readTimeout;
    int writeTimeout;
    int pingInterval;
    ……
}

这里我只列出了Builder中的属性,而我们配置的过程就是在对这些属性进行赋值操作,比如:

public Builder connectTimeout(long timeout, TimeUnit unit) {
      connectTimeout = checkDuration("timeout", timeout, unit);
      return this;
    }
public Builder addInterceptor(Interceptor interceptor) {
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      interceptors.add(interceptor);
      return this;
    }
public Builder addNetworkInterceptor(Interceptor interceptor) {
      if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
      networkInterceptors.add(interceptor);
      return this;
    }

这里就不全部展开说了,理解了OkHttpClient的创建方式,需要配置什么,找对应的方法就行了。
接着上面的请求流程,我们的OkHttpClient创建好之后,通过newCall(request)方法去获取一个Call对象来发送请求,该方法需要一个Request对象。所以我们下面就介绍下Request对象。

2 Request

这里Request泛指和请求相关的类,核心包括RequestHeaderRequestBody三个类,下面就针对这三个类进行简单介绍。
通常我们会通过如下方式进行Request构建(以POST为例,因为一般POST才会涉及请求体)

RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("title", "Square Logo")
        .addFormDataPart("image", "logo-square.png",
            RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
        .build();

    Request request = new Request.Builder()
        .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
        .url("https://api.imgur.com/3/image")
        .post(requestBody)
        .build();

可以看到一般是先通过构建RequestBody,然后通过Request.BuilderRequestBodyHeaders封装到Request中。
Headers相对比较简单,我们放在后面介绍。

2.1 RequestBody

我们看其类定义会发现其是一个抽象类:

public abstract class RequestBody {}

使用过程中真正构建的时候是使用它的实现类,常用的就是FormBodyMultipartBody分别对应表单提交和分块提交。

2.1.1 FormBody

FormBody的封装,是通过其内部类FormBody.Builder实现的,主要方法如下:

add(String name, String value):添加表单的信息的key(name)-value。这个方法添加的是为经编码的数据。
public Builder addEncoded(String name, String value):作用同上,只是添加的是已经编码之后的数据。
FormBody build():构建一个FormBody实例

2.1.2 MultipartBody

FormBody一样,也是通过内部类MultipartBody.Builder进行封装实现,主要方法如下:

setType(MediaType type):设置MIME类型
addPart(RequestBody body):直接添加一个RequestBody作为一个分块数据
addPart(@Nullable Headers headers, RequestBody body):添加Header和RequestBody作为一个分块数据
addFormDataPart(String name, String value):添加一个键值对作为表单格式的数据
addFormDataPart(String name, @Nullable String filename, RequestBody body):添加一个表单格式的数据块(一般是在上传文件的时候使用较多)
addPart(Part part):直接添加一个Part对象作为一个数据块

这里Part类是对分块数据的封装,一个Part对象就代表一个MultiBody中的分块数据
看到这里,你会发现,整个OkHttp框架设计,非常多的地方使用建造者设计模式。
除了这些OkHttp框架已经提供好的RequestBody的实现,我们平时使用的过程中,如果有特殊需要,我们也可以通过自定义RequestBody来满足要求,具体使用可以参考上一篇中的2.4.3——POST提交流的时候,有过简单实现。
接着我们看上面提到的Request中三大核心类之一的Headers

2.2 Headers

这个比较简单,里面就是通过String数组存放我们的请求头信息,这里为什么用数组而不用Map呢,因为HTTP协议中header一个key可以对应多个value,所以这里使用数组,然后每2个步长为一个header的key和value。感兴趣的朋友可以看下它的源码就明白了。
我们实际使用的时候,一般直接通过Request.Builderheader(String name, String value)addHeader(String name, String value)进行添加。具体区别,我们在第一篇基本使用中已经介绍了,这里就不再赘述。
接着看下真正的信息封装了Request类吧,这个才是真正承载请求信息的类。

2.3 Request类

我们还是看下官方对该类的定义吧

An HTTP request. Instances of this class are immutable if their {@link #body} is null or itself immutable.

很简单,代表一个HTTP协议的请求信息,而且还说明了该类是不可变的。什么意思呢,就说我们构造好一个Request后,就不能更改其属性,如果需要修改,我们需要通过重新构建一个新的Request来满足要求。
既然该类是请求信息的载体,那里面肯定就有我们的请求url、method,headers等信息的记录了。可以看到该类有如下几个属性:

public final class Request {
	final HttpUrl url; // 请求的url地址
	final String method; // 请求方法(GET/POST等)
	final Headers headers;// 请求头信息封装
	final @Nullable RequestBody body; // 请求体封装
……
}

我们可以看到,该类和其属性都是被final关键字修饰的,所以该类不能被继承,属性一旦初始化就不能修改,这也验证了上面对该类的描述(不可修改的特性)。
那这些属性是怎么封装进来的呢,同OkHttpClient一样,也是通过内部类Builder进行构建的,所以我们需要怎么配置Request就直接找Request.Builder中对应的方法就行了。这里就不详细展开说明了。
上面说到,该类的属性是不能修改的,既然不能修改,那如果我想在已有的请求信息基础上对某些属性进行修改怎么办呢,难道要全部重新构建一遍?当然不用,通过newBuilder()方法就能得到一个包含之前信息的Builder对象,我们在此基础上,对需要修改的部分重新赋值,再通过Builder.build()就能拿到新的Request了。
到这里,我们请求信息就算封装好了,然后将其交给newCall(request)方法就能得到一个Call对象。由于这里不是分析源码,所以不做特别说明,我们知道通过该方法,就会将Request中封装的信息,传递给Call,然后用Call发起真正的请求。

2 Call

为了便于说明,我们先来简单看下该类的源码吧。

public interface Call extends Cloneable {
  // 返回我们的请求封装信息
  Request request();

  // 同步执行请求
  Response execute() throws IOException;

  // 异步执行请求
  void enqueue(Callback responseCallback);

  // 取消请求,如果该请求已经被执行,是无法取消的。
  void cancel();

  // 判断当前请求是否已经被执行
  boolean isExecuted();

// 判断该请求是否被取消了
  boolean isCanceled();

  // 请求超时,超时时间通过OkHttpClient.Builder的callTimeout()方法设置
  Timeout timeout();

  ……
}

该类的核心方法,已经在代码里面注释的比较清楚了。我们通过该类真正发起请求,取消请求,并且可以判断当前请求的状态。
可以看到,这是一个接口,它的实现类是RealCall,还是那句话,这里不是做源码分析,所以如果想了解具体每个方法的实现,就请自己去这个类里面去查看。这里我们只需要知道每个方法的作用即可。
接着最开始那个请求的示例继续,得到Call对象后,不管是异步(enqueue()方法)还是同步(excute()方法)请求,最终我们都会得到Response这个对象。这个里面就是对返回信息的封装。

3 Response

该类和Request构成了HTTP请求中的请求和响应。所以根据前面对Request的介绍,估计诸位已经能猜出该类的设计了。是的,同Request一样,该类也是不可被继承,也不能被修改的。

public final class Response implements Closeable {
  final Request request;
  final Protocol protocol;
  final int code;
  final String message;
  final @Nullable Handshake handshake;
  final Headers headers;
  final @Nullable ResponseBody body;
  final @Nullable Response networkResponse;
  final @Nullable Response cacheResponse;
  final @Nullable Response priorResponse;
  final long sentRequestAtMillis;
  final long receivedResponseAtMillis;
  ……
}

可以看到,该类和其中的属性都被final修饰了。而且设计模式也一样,通过对应的Builder进行构建,如果需要在已有Response的基础上重新设置某些属性,通过其newBuilder()方法。
对HTTP协议稍微熟悉点的人,上面列出的属性应该都不会陌生。至于里面封装的另外三个Response属性,那个涉及到缓存、重定向等问题,这里不做详细讨论。一般我们拿到Response对象后,判断下返回码如果正常,直接拿到body属性,再通过ResponseBody.string()就能获读取到返回信息了。
不过这里有个注意点,就是这个string()方法,同一个ReponseBody对象只能调用一次,里面的数据一旦被读走,就没了,再次调用会报错哦,所以如果你需要重复使用,就需要自己读出来后做好备份工作了。

到此,我们对整个请求过程中国涉及到的一些类就做了简单介绍,由于这里并不是做详细的流程分析和源码分析,只是让大家对整个流程有个大概的认识,了解一些常用的API,然后对其中一些使用注意点进行说明,所以介绍的相对比较简单和粗糙,需要深入了解的朋友,可以看后续的源码分析篇。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值