OkHttp使用介绍

来源:互联网 发布:java有多少关键字 编辑:程序博客网 时间:2024/06/15 05:49

    最近对应用的网络模块进行重构,从原有HttpClient切换到OkHttp;在此对OkHttp的使用做一个简单的总结,方便后续查阅。

官网地址:http://square.github.io/okhttp/
GitHub地址:https://github.com/square/okhttp

OkHttp框架是一个基于http协议(http协议介绍)的网络请求框架,实现的主要功能,

  • 网络请求的调度
  • 请求线程的复用
  • 请求连接的复用
  • 缓存策略的实现
  • 网络路由的实现
  • 拦截器

本文站在Http的角度对OkHttp的使用做一个简单的介绍。


OkHttp的配置


gradle配置

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

ProGuard配置

-dontwarn okio.**-dontwarn javax.annotation.Nullable-dontwarn javax.annotation.ParametersAreNonnullByDefault


Request


    每一个Http请求都包含一个请求行和请求头,也可能包含请求正文。在OkHttp中通过Request类表示一个http请求,采用构建者设计模式通过一个Request.Builder来构建一个Request.

public final class Request {  final HttpUrl url;  final String method;  final Headers headers;  final RequestBody body;  final Object tag;    public static class Builder {        HttpUrl url;        String method;        Headers.Builder headers;        RequestBody body;         public Request build() {              if (url == null) throw new IllegalStateException("url == null");          return new Request(this);        }    }    ...省略代码... }

通过Builder构建一个Request

Request.Builder builder = new Request.Builder();...构建步骤url/method等...Request request = builder.build();

请求行

builder.url(url);//设置urlbuilder.get();//设置请求方法为GET,也可以通过builder.method("GET",null)进行设置

请求头Headers

builder.addHeader("User-Agent","android 8.0");//设置User-Agentbuilder.removeHeader("Cache-Control");//从Headers中移除Cache-Control

请求正文RequestBody

//请求正文为String类型String content = "XXXXXXXXXXXXX";//请求正文内容RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"),content);//请求正文为byte类型byte[] bytes;//请求正文内容,需要初始化复制哈RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),bytes);//请求正文为File类型(一般指上传文件之类的)File file = new File("pathXXX");RequestBody requestBody = RequestBody.create(MediaType.parse(" image/png"),bytes);

构建一个完整的请求Request

String content = "构建一个完整的OkHttp Request";//构建RequestBodyRequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"),content);Request.Builder builder = new Request.Builder();//设置url、method、header等builder.url("http://XXX").post(requestBody).addHeader("Cache-Control","no-cache");//构建RequestRequest request = builder.build();


Call


在OkHttp中,通过Call来执行一个Request,其真正的实现在RealCall中实现,具体逻辑到后面的源码分析阶段在分析。

OkHttpClient okHttpClient = new OkHttpClient();Call call = okHttpClient.newCall(request);Response response = call.execute();

Call提供了同步异步两种执行方式。

Call异步执行

Call异步执行,调用enqueue(callback)函数,将请求加入到请求队列当中去,通过callback来监控请求的执行进度

OkHttpClient okHttpClient = new OkHttpClient();Call call = okHttpClient.newCall(request);call.enqueue(new okhttp3.Callback() {   @Override   public void onFailure(Call call, IOException e) {   }   @Override   public void onResponse(Call call, Response response) throws IOException {   }});

onFailure:请求失败,这里的失败是指OkHttp执行失败,而不是服务端对请求返回code表示失败。
onResponse:表示与服务端请求通信成功,通过解析返回的response来解析服务端返回的具体结果

Call同步执行
Call同时提供了同步执行,调用execute()函数进行同步执行,同步执行会阻塞当前的线程,直到请求结果返回,因此要注意不要在UI线程中执行。execute()的返回值是Response;若请求失败为null,请求成功则对response进行解析。

OkHttpClient okHttpClient = new OkHttpClient();Call call = okHttpClient.newCall(request);Response response = call.execute();//对response进行解析

Call取消请求

Call同时支持取消,对正在执行的请求进行取消操作

OkHttpClient okHttpClient = new OkHttpClient();Call call = okHttpClient.newCall(request);Response response = call.execute();//突然不想执行了call.cancel();

执行cancel()后,若是通过enqueue(callback)进行异步执行,则会调用callback的onFailure;若是同步执行,call.execute()返回的结果为null.

Response


    Http请求与服务端正常通信之后会对客户端进行响应,在OkHttp中,将服务端的响应封装在Response中返回给上层,上层通过解析Response来获取服务端返回的数据。

public final class Response implements Closeable {  final Request request;//对应的请求  final Protocol protocol;  final int code;  final String message;  final Handshake handshake;  final Headers headers;  final ResponseBody body;  final Response networkResponse;  final Response cacheResponse;  final Response priorResponse;  final long sentRequestAtMillis;//发送请求的时间  final long receivedResponseAtMillis;//接受服务端数据的时间...省略代码若干...}

状态行

Response中的code和message分别表示状态行的状态码与状态码描述

 final int code; final String message;

判断服务端是否成功响应客户端的请求有两种方式:
第一种:通过response.code的值,来表示判断此次请求服务端是否正常响应
第二种:调用response.isSuccessful(),其内部也是通过比较code的值,在[200,300)之间返回true

响应头

Response将响应头的信息封装在Headers中,通过header(name)读取响应头中的信息

Response response = call.execute();//读取Cache-Control信息String cacheControl = response.header("Cache-Control");//读取Expires信息String expires = response.header("Expires");

响应正文

Response将响应正文的信息封装在ResponseBody中,通过ResponseBody读取响应正文中的信息,读取信息有三种方式,

Response response = call.execute();//第一种方式:通过bytes()函数获取字节数组byte[] data = response.body().bytes();//第二种方式:通过string()获取字符串String result = response.body().string();//第三种方式:通过byteStream()获取InputStream,从流中读取数据InputStream stream = response.body().InputStream();

注意事项:
1.第一种方式获取字节数组,会将整个响应正文都加载到内存;但对于比较大的响应正文(例如100M的文件),很有可能会导致OutOfMemoryError,此种情况下应该使用InputStream()代替。

2.第二种方式是直接将响应正文转化为字符串返回,但是对于非字符串或者某些加密过的字符串,则不能直接调用byte()来代替。同时所有数据也会被加载到内存当中,存在第一种方式引发OutOfMemoryError的可能。

3.第三种方式一般适合于文件等比较大,不适合全部都加载到内存的响应正文,例如文件下载等。


完整代码片段示例


抓取https://www.baidu.com/的内容

Request.Builder builder = new Request.Builder();Request request = builder.url("https://www.baidu.com/").get().build();OkHttpClient okHttpClient = new OkHttpClient();Call call = okHttpClient.newCall(request);call.enqueue(new okhttp3.Callback() {   @Override   public void onFailure(Call call, IOException e) {       //抓取失败处理   }   @Override   public void onResponse(Call call, Response response) throws IOException {           //判断是否抓取成功       if(response != null && response.isSuccessful()) {            String content = response.body().string();            //content为百度主页的内容        }   }});



若要了解文件的上传下载、表单等等的实现,可以参考OkHttp在Github上的WiKi。