【185】okHttp 3.0 基本使用整理

0.okHttp点滴

【1】网络请求属于耗时请求,不能放在ui线程(主线程)执行,需要放在子线程中执行。

1.GET请求--默认请求

 1     /**
 2      * [1]GET请求
 3      */
 4     private void okHttpGet(String url) throws IOException {
 5         //1,创建okHttpClient对象
 6         OkHttpClient client = new OkHttpClient();
 7 
 8 
 9         //2,创建一个Request
10         //可以通过Request.Builder设置更多的参数比如: header、 method等
11         Request request = new Request.Builder()
12                 .get()  //get请求;
13                 .url(url)
14                 .build();
15 
16         //3,新建一个call对象
17         Call call = client.newCall(request);
18         //[4-1]同步请求-会阻塞,使用很少;
19         call.execute();
20         //[4-2]异步请求-请求是在线程,更新数据需要使用handler等;
21         //请求加入调度,这里是异步Get请求回调
22         call.enqueue(new Callback() {
23             @Override
24             public void onFailure(Call call, IOException e) {
25 
26             }
27 
28             @Override
29             public void onResponse(Call call, Response response) throws IOException {
30                 //可以判断response返回的状态:
31                 if (response.isSuccessful()) {
32                     //response.body返回数据;
33                     //[1]
34                     String string = response.body().string();
35                     //                [2]
36                     byte[] bytes = response.body().bytes();
37                     //                [3]
38                     InputStream inputStream = response.body().byteStream();
39                     //                [4]
40                     Reader reader = response.body().charStream();
41                     //                [5]
42                     BufferedSource source = response.body().source();
43                 }
44 
45             }
46         });
47 
48     }

【说明】

【1】发送一个GET请求的步骤,首先构造一个Request对象,参数至少具备URL,当然也可以通过Request.Builder设置更多的参数比如:headermethod等。 

 1 //URL带的参数
 2 HashMap<String,String> params = new HashMap<>();
 3 //GET 请求带的Header
 4 HashMap<String,String> headers= new HashMap<>();
 5 //HttpUrl.Builder构造带参数url
 6  HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
 7         if (params != null) {
 8 
 9             for (String key : params.keySet()) {
10                 urlBuilder.setQueryParameter(key, params.get(key));
11             }
12         }
13         Request request = new Request.Builder()
14                 .url(urlBuilder.build())
15                 .headers(headers == null ? new Headers.Builder().build() : Headers.of(headers))
16                 .get()
17                 .build();

【2】通过Request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute(),enqueue()cancel()等方法。
execute():同步GET请求

1  //同步
2 Response response = call.execute()
3      if(response.isSuccessful()){
4       //响应成功
5 }

enqueue():异步GET请求,将call加入调度队列,然后等待任务执行完成,在Callback中即可得到结果。

 1 call.enqueue(new Callback() {
 2             @Override
 3             public void onFailure(Call call, IOException e) {
 4 
 5             }
 6 
 7             @Override
 8             public void onResponse(Call call, Response response) throws IOException {
 9                 //可以判断response返回的状态:
10                 if (response.isSuccessful()) {
11                     //response.body返回数据;
12                 }
13 
14             }
15         });

cancel():Call请求的取消,okHttp支持请求取消功能,当调用请求的cancel()时,请求就会被取消,抛出异常。

又是需要监控许多Http请求的执行情况,可以把这些请求的Call搜集起来,

执行完毕自动剔除,如果在请求执行过程中(如下载),想取消执行,可使用call.cancel()取消。

【3】请求的响应Response
对于同步GET请求,Response对象是直接返回的。

异步GET请求,通过onResponse回调方法传参数,需要注意的是这个onResponse回调方法不是在主线程回调,可以使用runInUIThread(new Runnable(){})
获得,可以通过 response.body().string() 获取;

 1 //[4-2]异步请求-请求是在线程,更新数据需要使用handler等;
 2         //请求加入调度,这里是异步Get请求回调
 3         call.enqueue(new Callback() {
 4             @Override
 5             public void onFailure(Call call, IOException e) {
 6 
 7             }
 8 
 9             @Override
10             public void onResponse(Call call, Response response) throws IOException {
11                 //可以判断response返回的状态:
12                 if (response.isSuccessful()) {
13                     //response.body返回数据;
14                     //[1]返回的字符串
15                     String string = response.body().string();
16                     //[2]返回的二进制字节数组 
17                     byte[] bytes = response.body().bytes();
18                     //[3]返回的inputStream 
19                     InputStream inputStream = response.body().byteStream();
20                     //[4]
21                     Reader reader = response.body().charStream();
22                     //[5]
23                     BufferedSource source = response.body().source();
24                 }
26             }
27         });

2.post 提交键值对

【post创建的说明】

post请求创建request和get是一样的,只是post请求需要提交一个表单,就是RequestBody。表单的格式有好多种。

【提交键值对】

 1 /**
 2      * [2]post 提交键值对
 3      */
 4     private void okHttpPostWithParam(String url) {
 5         OkHttpClient okHttpClient = new OkHttpClient();
 6 
 7         /*okhttp2 的写法;
 8         FormEncodingBuilder builder = new FormEncodingBuilder();
 9         builder.add("username", "CodingMankk");*/
10 
11         //okhttp3的写法
12         FormBody formBody = new FormBody.Builder()
13                 .add("username", "admin")
14                 .add("password", "admin")
15                 .build();
16 
17         Request request = new Request.Builder()
18                 .url(url)
19                 .post(formBody)
20                 .build();
21 
22         Call call = okHttpClient.newCall(request);
23 
24         //[1]同步请求
25         /*try {
26             call.execute();
27         } catch (IOException e) {
28             e.printStackTrace();
29         }*/
30 
31         //[2]异步请求
32         call.enqueue(new Callback() {
33             @Override
34             public void onFailure(Call call, IOException e) {
35                 //请求失败的回调
36             }
37 
38             @Override
39             public void onResponse(Call call, Response response) throws IOException {
40                 //请求成功的回调;
41                 //                response 是请求到的数据;
42             }
43         });
44     }

3.post 提交表单

使用 FormEncodingBuilder(2.0)FormBody(3.0) 来构建和HTML <form> 标签相同效果的请求体。

用户注册的情况,需要你输入用户名,密码,还有上传头像,这其实就是一个表单,
主要的区别就在于构造不同的RequestBody传递给post方法即可

表单数据的提交需要:compile 'com.squareup.okio:okio:1.11.0'

MuiltipartBody,是RequestBody的一个子类,提交表单利用MuiltipartBody来构建一个RequestBody,
下面的代码是发送一个包含用户民、密码、头像的表单到服务端

【注意】
【1】如果提交的是表单,一定要设置setType(MultipartBody.FORM)这一句
【2】 addFormDataPart("avatar","avatar.png",requestBodyFile)
 参数1:类似于键值对的键,是供服务端使用的,就类似于网页表单里面的name属性,<input type="file" name="myfile">
 参数2:本地文件的名字
 参数3:第三个参数是RequestBody,里面包含了我们要上传的文件的路径以及MidiaType
【3】本地sd卡的读写权限的添加:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 1 private void okHttpPostFormData(String url) {
 2         //构造图片文件;
 3         File file = new File(Environment.getExternalStorageDirectory(), "avatar.png");
 4         if (!file.exists()) {
 5             Log.d("okHttpPostFormData", "文件不存在");
 6             return;
 7         }
 8 
 9         RequestBody requestBodyFile =
10                 RequestBody.create(MediaType.parse("application/octet-stream"), file);
11 
12         MultipartBody multipartBody = new MultipartBody.Builder()
13                 //一定要设置这句
14                 .setType(MultipartBody.FORM)
15                 .addFormDataPart("username", "admin")
16                 .addFormDataPart("password", "admin")
17                 .addFormDataPart("avatar", "avatar.png", requestBodyFile)
18                 .build();
19 
20         Request request = new Request.Builder()
21                 .url(url)
22                 .post(multipartBody)
23                 .build();
24 
25         OkHttpClient okHttpClient = new OkHttpClient();
26         Call call = okHttpClient.newCall(request);
27         //[1]同步请求;
28        /* try {
29             call.execute();
30         } catch (IOException e) {
31             e.printStackTrace();
32         }*/
33 
34         //[2]异步请求
35         call.enqueue(new Callback() {
36             @Override
37             public void onFailure(Call call, IOException e) {
38 
39             }
40 
41             @Override
42             public void onResponse(Call call, Response response) throws IOException {
43 
44             }
45         });
46 
47     }

【多种类型的multipartBody的构造】

【1】图片文件+字符串;

 1        //构造图片文件;
 2         File file = new File(Environment.getExternalStorageDirectory(), "avatar.png");
 3         if (!file.exists()) {
 4             Log.d("okHttpPostFormData", "文件不存在");
 5             return;
 6         }
 7 
 8         RequestBody requestBodyFile =
 9                 RequestBody.create(MediaType.parse("application/octet-stream"), file);
10 
11         MultipartBody multipartBody = new MultipartBody.Builder()
12                 //一定要设置这句
13                 .setType(MultipartBody.FORM)
14                 .addFormDataPart("username", "admin")
15                 .addFormDataPart("password", "admin")
16                 .addFormDataPart("avatar", "avatar.png", requestBodyFile)
17                 .build();
18         
19         Request request = new Request.Builder()
20                 .url(url)
21                 .post(multipartBody)
22                 .build();

【2】多个string字符串

 Post的时候,参数是包含在请求体中的,通过MultipartBody.Builder 添加多个String键值对,然后去构造RequestBody,最后完成Request的构造

 1         //POST参数构造MultipartBody.Builder,表单提交
 2         HashMap<String, String> params = new HashMap<>();
 3         MultipartBody.Builder MultipartBodyBuilder  = new MultipartBody.Builder()
 4                                               .setType(MultipartBody.FORM);
 5         if (params != null) {
 6             for (String key : params.keySet()) {
 7                 if (params.get(key) != null) {
 8                     MultipartBodyBuilder.addFormDataPart(key, params.get(key));
 9                 }
10             }
11         }
12 
13         // 构造Request->call->执行
14         Request request = new Request.Builder()
15                 .url(url)
16                 .post(MultipartBodyBuilder.build())//参数放在body体里
17                 .build();

3.post 文件上传

3.1 RequestBody的构造

上传文件本身也是一个POST请求。在上面的POST请求中可以知道,POST请求的所有参数都是在BODY体中的,

请求体的源码RequestBody:请求体=contentType +BufferedSink

RequestBody源码

【简析】源码中看出,该类是一个抽象类,需要实现;其中具有三个抽象方法;下面是5个Request的create方法。

  1 //抽象类请求体,**请求体=contentType + BufferedSink**
  2 public abstract class RequestBody {
  3   /** Returns the Content-Type header for this body. */
  4  //【抽象方法1】返回Body体的内容类型
  5   public abstract @Nullable MediaType contentType();
  7   /**
  8    * Returns the number of bytes that will be written to {@code sink} in a call to {@link #writeTo},
  9    * or -1 if that count is unknown.
 10    */
 11   //【抽象方法2】返回写入sink的字节长度
 12   public long contentLength() throws IOException {
 13     return -1;
 14   }
 15 
 16   /** Writes the content of this request to {@code sink}. */
 17   //【抽象方法3】写入缓存sink
 18   public abstract void writeTo(BufferedSink sink) throws IOException;
 19 
 20   /**
 21    * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null
 22    * and lacks a charset, this will use UTF-8.
 23    */
 24    //【创建的请求体1】创建一个请求体,如果contentType不等于null且缺少字符集,将使用UTF-8
 25   public static RequestBody create(@Nullable MediaType contentType, String content) {
 26     Charset charset = Util.UTF_8;
 27     if (contentType != null) {
 28       //contentType里面的字符集
 29       charset = contentType.charset();
 30       if (charset == null) {
 31         charset = Util.UTF_8;
 32         //contentType 里面加入字符集
 33         contentType = MediaType.parse(contentType + "; charset=utf-8");
 34       }
 35     }
 36     //按字符集变成字节
 37     byte[] bytes = content.getBytes(charset);
 38     return create(contentType, bytes);
 39   }
 40 
 41   /** Returns a new request body that transmits {@code content}. */
 42  //【创建的请求体2】创建新的请求体,传输字节
 43   public static RequestBody create(
 44       final @Nullable MediaType contentType, final ByteString content) {
 45     return new RequestBody() {
 46       @Override public @Nullable MediaType contentType() {
 47         //请求体需要的内容类型
 48         return contentType;
 49       }
 50 
 51       @Override public long contentLength() throws IOException {
 52        //写入BufferedSink 的长度
 53         return content.size();
 54       }
 55 
 56       @Override public void writeTo(BufferedSink sink) throws IOException {
 57        //将需要传输的字节,写入缓存BufferedSink 中
 58         sink.write(content);
 59       }
 60     };
 61   }
 62 
 63   /** 【创建的请求体3】Returns a new request body that transmits {@code content}. */
 64   public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) {
 65     return create(contentType, content, 0, content.length);
 66   }
 67 
 68   /**【创建的请求体4】 Returns a new request body that transmits {@code content}. */
 69   public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,
 70       final int offset, final int byteCount) {
 71     if (content == null) throw new NullPointerException("content == null");
 72     Util.checkOffsetAndCount(content.length, offset, byteCount);
 73     return new RequestBody() {
 74       @Override public @Nullable MediaType contentType() {
 75         return contentType;
 76       }
 77 
 78       @Override public long contentLength() {
 79         return byteCount;
 80       }
 81 
 82       @Override public void writeTo(BufferedSink sink) throws IOException {
 83         sink.write(content, offset, byteCount);
 84       }
 85     };
 86   }
 87 
 88   /** Returns a new request body that transmits the content of {@code file}. */
 89   //【创建的请求体5】创建一个请求体,传输文件file内容,其实就是file写入bufferedSink
 90   public static RequestBody create(final @Nullable MediaType contentType, final File file) {
 91     if (file == null) throw new NullPointerException("content == null");
 92 
 93     return new RequestBody() {
 94       @Override public @Nullable MediaType contentType() {
 95         return contentType;
 96       }
 97 
 98       @Override public long contentLength() {
 99         return file.length();
100       }
101 
102       @Override public void writeTo(BufferedSink sink) throws IOException {
103         Source source = null;
104         try {
105          //文件写入BufferedSink 
106           source = Okio.source(file);
107           sink.writeAll(source);
108         } finally {
109           Util.closeQuietly(source);
110         }
111       }
112     };
113   }
114 }

 

【MultipartBody】
1. MultipartBody本质一个是一个RequestBody,具有自己的contentType+BufferedSink,是POST请求的最外层封装,需要添加多个Part;

 

2. Part对象组成:Headers+RequestBody。是MultipartBody的成员变量,需要写入MultipartBodyBufferedSink中。

Http请求中Content-Type
客户端在进行http请求服务器的时候,需要告诉服务器请求的类型,服务器在返回给客户端的数据的时候,也需要告诉客户端返回数据的类型默认的ContentType为text
/html 也就是网页格式.

常用的内容类型 text
/plain :纯文本格式 .txt text/xml : XML格式 .xml image/gif :gif图片格式 .gif image/jpeg :jpg图片格式 .jpg image/png:png图片格式 .png audio/mp3 : 音频mp3格式 .mp3 audio/rn-mpeg :音频mpga格式 .mpga video/mpeg4 : 视频mp4格式 .mp4 video/x-mpg : 视频mpa格式 .mpg video/x-mpeg :视频mpeg格式 .mpeg video/mpg : 视频mpg格式 .mpg
以application开头的媒体格式类型: application
/xhtml+xml :XHTML格式 application/xml : XML数据格式 application/atom+xml :Atom XML聚合格式 application/json : JSON数据格式 application/pdf :pdf格式 application/msword : Word文档格式 application/octet-stream : 二进制流数据(如常见的文件下载)

RequestBody的数据格式都要指定Content-Type,常见的有三种

application/x-www-form-urlencoded 数据是个普通表单
multipart/form-data 数据里有文件
application/json 数据是个json

普通表单并没有指定Content-Type,这是因为FormBody继承了RequestBody,它已经指定了数据类型为application/x-www-form-urlencoded。 

[普通表单]

RequestBody body = new FormBody.Builder()
.add("键", "值")
.add("键", "值")
...
.build();

[json表单 ]

1 MediaType JSON = MediaType.parse("application/json; charset=utf-8");
2 RequestBody body = RequestBody.create(JSON, "你的json");

[数据包含文件 ]

1 RequestBody requestBody = new MultipartBody.Builder()
2                                            .setType(MultipartBody.FORM)
3                                            .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/png")
4                                            .build()

MultipartBody也是继承了RequestBody,看下源码可知它适用于这五种ContentType: 

public static final MediaType MIXED = MediaType.parse("multipart/mixed");
public static final MediaType ALTERNATIVE = MediaType.parse("multipart/alternative");
public static final MediaType DIGEST = MediaType.parse("multipart/digest");
public static final MediaType PARALLEL = MediaType.parse("multipart/parallel");
public static final MediaType FORM = MediaType.parse("multipart/form-data");

 

其他的媒体类型支持参考下面网址中列出的MIME类型:http://www.w3school.com.cn/media/media_mimeref.asp

3.2 单个文件上传

【简单示例】将sd卡的文件读取,然后构造fileBody,使用post请求上传。 

 1 /**
 2      * [3]post http文件上传
 3      * 最主要的还是创建合适的RequestBody
 4      */
 5     private void okHttpPostFile(String url) {
 6 
 7         OkHttpClient okHttpClient = new OkHttpClient();
 8 
 9         //读取外部的sd卡的文件上传;
10         File file = new File(Environment.getExternalStorageDirectory(), "mimi.mp4");
11         RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"),
12                 file);
13 
14         Request request = new Request.Builder()
15                 .url(url)
16                 .post(fileBody)
17                 .build();
18 
19         Call call = okHttpClient.newCall(request);
20 
21         //[1]同步请求;
22        /* try {
23             call.execute();
24         } catch (IOException e) {
25             e.printStackTrace();
26         }*/
27 
28         //[2]异步请求
29         call.enqueue(new Callback() {
30             @Override
31             public void onFailure(Call call, IOException e) {
32 
33             }
34 
35             @Override
36             public void onResponse(Call call, Response response) throws IOException {
37 
38             }
39         });
40     }

3.3 多个文件的上传

【重点】RequestBody create(MediaType contentType, final File file)构造文件请求体RequestBody ,并且添加到MultiPartBody  

 1 /**
 2      * [多个文件的上传]
 3      */
 4 
 5     private void postMultiFile(String url){
 6 
 7         HashMap<String, String> urlHeaders = new HashMap<>();
 8         
 9         OkHttpClient client = new OkHttpClient();
10 
11         // form 表单形式上传,MultipartBody的内容类型是表单格式,multipart/form-data
12         MultipartBody.Builder multiPartBodyBuilder= new MultipartBody
13                 .Builder()
14                 .setType(MultipartBody.FORM);
15 
16         //参数
17         HashMap<String,String> params = new HashMap<>();
18         if (params != null) {
19             for (String key : params.keySet()) {
20                 if (params.get(key)!=null){
21                     //增加一系列的参数;
22                     multiPartBodyBuilder.addFormDataPart(key, params.get(key));
23                 }
24             }
25         }
26         
27         //需要上传的文件,需要携带上传的文件(小型文件 不建议超过500K)
28         HashMap<String,String> files= new HashMap<>();
29         if (files != null) {
30             for (String key : files.keySet()) {
31                 //重点:RequestBody create(MediaType contentType, final File file)构造文件请求体RequestBody
32                 RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), files.get(key));
33                 multiPartBodyBuilder.addFormDataPart(key, files.get(key).getClass().getName(),requestBody);
34             }
35         }
36         
37         //构造请求request
38         Request request = new Request.Builder()
39                 .headers(urlHeaders == null ? new Headers.Builder().build() : Headers.of(urlHeaders))
40                 .url(url)
41                 .post(multiPartBodyBuilder.build())
42                 .build();
43         
44         //异步执行请求
45         client.newCall(request).enqueue(new Callback() {
46             @Override
47             public void onFailure(Call call, IOException e) {
48                 
49             }
50 
51             @Override
52             public void onResponse(Call call, Response response) throws IOException {
53                 //非主线程
54                 if (response.isSuccessful()) {
55                     String str = response.body().string();
56                     Log.i("tk", response.message() + " , body " + str);
57 
58                 } else {
59                     Log.i("tk" ,response.message() + " error : body " + response.body().string());
60                 }
61             }
62         });
63     }

 

 

6.post json 请求

 1 /**
 2      * [5]post json 请求;
 3      */
 4     private void okHttpPostJSon(String url, String json) throws IOException {
 5 
 6         OkHttpClient okHttpClient = new OkHttpClient();
 7 
 8         MediaType JSON = MediaType.parse("application/json; charset=utf-8");
 9         RequestBody requestBody = RequestBody.create(JSON, json);
10 
11         Request request = new Request.Builder()
12                 .url(url)
13                 .post(requestBody)
14                 .build();
15 
16         Call call = okHttpClient.newCall(request);
17         //[1]同步请求;
18         call.execute();
19         //[2]异步请求;
20         call.enqueue(new Callback() {
21             @Override
22             public void onFailure(Call call, IOException e) {
23 
24             }
25 
26             @Override
27             public void onResponse(Call call, Response response) throws IOException {
28 
29             }
30         });
31 
32     }

7.使用Gson来解析JSON响应

 1 /**
 2      * [6]使用Gson来解析JSON响应
 3      * <p>
 4      * Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析Github API的JSON响应。
 5      * 注意: ResponseBody.charStream() 使用响应头 Content-Type 指定的字符集来解析响应体。默认是UTF-8。
     * 添加依赖: compile 'com.google.code.gson:gson:2.6.2'
6 */ 7 private void ParseGson(String url) { 8 OkHttpClient okHttpClient = new OkHttpClient(); 9 10 final Gson gson = new Gson(); 11 12 //默认是get请求; 13 final Request request = new Request.Builder() 14 .url("https://api.github.com/gists/c2a7c39532239ff261be") 15 .build(); 16 17 Call call = okHttpClient.newCall(request); 18 19 call.enqueue(new Callback() { 20 @Override 21 public void onFailure(Call call, IOException e) { 22 23 } 24 25 @Override 26 public void onResponse(Call call, Response response) throws IOException { 27 if (!response.isSuccessful()) 28 throw new IOException("Unexpected code " + response); 29 Gist gist = gson.fromJson(response.body().charStream(), Gist.class); 30 for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) { 31 System.out.println(entry.getKey()); 32 System.out.println(entry.getValue().content); 33 } 34 } 35 }); 38 } 39 40 private static class Gist { 41 Map<String, GistFile> files; 42 } 43 44 private static class GistFile { 45 String content; 46 }

8.get请求文件下载

 1 /**
 2      * [6] get请求文件下载
 3      * 此处的实例是下载图片
 4      */
 5     private void okHttpGetDownLoadFile(String url) {
 6         OkHttpClient okHttpClient = new OkHttpClient();
 7         final Request request = new Request.Builder()
 8                 .get()
 9                 .url(url)
10                 .build();
11 
12         Call call = okHttpClient.newCall(request);
13         call.enqueue(new Callback() {
14             @Override
15             public void onFailure(Call call, IOException e) {
16 
17             }
18 
19             @Override
20             public void onResponse(Call call, Response response) throws IOException {
21                 //拿到图片的字节流,然后保存为了本地的一张图片
22                 if (response.isSuccessful()) {
23                     //获取数据流;
24                     InputStream is = response.body().byteStream();
25 
26                     //读到文件中;
27                     int len = 0;
28                     File file = new File(Environment.getExternalStorageDirectory(), "downLoadFile" +
29                             ".png");
30                     FileOutputStream fos = new FileOutputStream(file);
31 
32                     byte[] buf = new byte[1024];
33                     while ((len = is.read(buf)) != -1) {
34                         fos.write(buf, 0, len);
35                     }
36                     fos.flush();
37                     fos.close();
38                     is.close();
39                 }
40 
41 
42            /*   直接将图片设置给了ImagView;
43                 final Bitmap bitmap = BitmapFactory.decodeStream(is);
44                 runOnUiThread(new Runnable() {
45                     @Override
46                     public void run() {
47                         imageView.setImageBitmap(bitmap);
48                     }
49                 });
50                 is.close();*/
51             }
52         });
53 
54 
55     }

9.给文件的下载加上进度条

 1 /**
 2      * [7] 给文件的下载加上进度条
 3      * 进度的获取是在回调函数onResponse()中去获取
 4      * (1)使用response.body().contentLength()拿到文件总大小
 5      * (2)在while循环中每次递增我们读取的buf的长度
 6      */
 7 
 8     private void okHttpDownLoadWithProgress(String url) {
 9         OkHttpClient okHttpClient = new OkHttpClient();
10         final Request request = new Request.Builder()
11                 .get()
12                 .url(url)
13                 .build();
14 
15         Call call = okHttpClient.newCall(request);
16         call.enqueue(new Callback() {
17             @Override
18             public void onFailure(Call call, IOException e) {
19 
20             }
21 
22             @Override
23             public void onResponse(Call call, Response response) throws IOException {
24                 //拿到图片的字节流,然后保存为了本地的一张图片
25                 if (response.isSuccessful()) {
26                     //获取数据流;
27                     InputStream is = response.body().byteStream();
28 
29                     //每次下载的实时更新的进度;
30                     long sum = 0;
31                     //下载的文件总长度;
32                     final long total = response.body().contentLength();
33 
34                     //读到文件中;
35                     int len = 0;
36                     File file = new File(Environment.getExternalStorageDirectory(), "downLoadFile" +
37                             ".png");
38                     FileOutputStream fos = new FileOutputStream(file);
39 
40                     byte[] buf = new byte[1024];
41                     while ((len = is.read(buf)) != -1) {
42                         fos.write(buf, 0, len);
43 
44                         sum += len;
45                         final long finalSum = sum;
46                         Log.d("okHttp", "下载进度:" + finalSum + "/" + total);
47 
48                         //将进度设置到主线程显示
49                        /* runOnUiThread(new Runnable() {
50                             @Override
51                             public void run() {
52                                 //将进度设置到TextView中
53                                 contentTv.setText(finalSum + "/" + total);
54                             }
55                         });*/
56 
57                     }
58                     fos.flush();
59                     fos.close();
60                     is.close();
61                 }
62             }
63 
64         });
65 
66     }

【另外一种写法】

 1  /**
 2      * @param url 下载连接
 3      * @param saveDir 储存下载文件的SDCard目录
 4      * @param params url携带参数
 5      * @param extraHeaders 请求携带其他的要求的headers
 6      * @param listener 下载监听
 7      */
 8     public void download(final String url, final String saveDir, 
 9                          HashMap<String,String> params, HashMap<String,String> extraHeaders,
10                                  final OnDownloadListener listener) {
11 
12         OkHttpClient okHttpClient = new OkHttpClient();
13         //构造请求Url
14         HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
15         if (params != null) {
16             for (String key : params.keySet()) {
17                 if (params.get(key)!=null){
18                     urlBuilder.setQueryParameter(key, params.get(key));//非必须
19                 }
20             }
21         }
22         //构造请求request
23         Request request = new Request.Builder()
24                 .url(urlBuilder.build())
25                 .headers(extraHeaders == null ? new Headers.Builder().build() : Headers.of(extraHeaders))//headers非必须
26                 .get()
27                 .build();
28         
29         //异步执行请求
30         okHttpClient.newCall(request).enqueue(new Callback() {
31             @Override
32             public void onFailure(Call call, IOException e) {
33                 // 下载失败
34                 listener.onDownloadFailed();
35             }
36             @Override
37             public void onResponse(Call call, Response response) throws IOException {
38                 //非主线程
39                 InputStream is = null;
40                 byte[] buf = new byte[2048];
41                 int len = 0;
42                 FileOutputStream fos = null;
43                 // 储存下载文件的目录
44                 String savePath = isExistDir(saveDir);
45                 try {
46                     //获取响应的字节流
47                     is = response.body().byteStream();
48                     //文件的总大小
49                     long total = response.body().contentLength();
50                     File file = new File(savePath);
51                     fos = new FileOutputStream(file);
52                     long sum = 0;
53                     //循环读取输入流
54                     while ((len = is.read(buf)) != -1) {
55                         fos.write(buf, 0, len);
56                         sum += len;
57                         int progress = (int) (sum * 1.0f / total * 100);
58                         // 下载中
59                         if(listener != null){
60                             listener.onDownloading(progress);
61                         }
62 
63                     }
64                     fos.flush();
65                     // 下载完成
66                     if(listener != null){
67                         listener.onDownloadSuccess();
68                     }
69 
70                 } catch (Exception e) {
71                     if(listener != null){
72                         listener.onDownloadFailed();
73                     }
74 
75                 } finally {
76                     try {
77                         if (is != null)
78                             is.close();
79                     } catch (IOException e) {
80                     }
81                     try {
82                         if (fos != null)
83                             fos.close();
84                     } catch (IOException e) {
85                     }
86                 }
87             }
88         });
89     }

10.文件的上传增加进度

 1 /**
 2      * [8]文件的上传增加进度
 3      * 对于上传的进度的处理会比较麻烦,因为具体的上传过程是在RequestBody中由OkHttp帮我们处理上传,
 4      * 而且OkHttp并没有给我们提供上传进度的接口,这里做法是自定义类继承RequestBody,
 5      * 然后重写其中的方法,将其中的上传进度通过接口回调暴露出来供使用
 6      * 详见:包下的progressRequestBody类;
 7      * 在原有的RequestBody上包装了一层,最后在我们的使用中在post()方法中传入我们的CountingRequestBody对象即可
 8      * <p>
 9      * 最主要的还是创建合适的RequestBody
10      */
11     private void okHttpPostFileWithProgress(String url) {
12 
13         OkHttpClient okHttpClient = new OkHttpClient();
14 
15         //读取外部的sd卡的文件上传;
16         File file = new File(Environment.getExternalStorageDirectory(), "mimi.mp4");
17         //        RequestBody fileBody = RequestBody.create(MediaType.parse
18         // ("application/octet-stream"),file);
19 
20         //*****此处使用的RequestBody是经过修改;
21         RequestBody fileBody = progressRequestBody.create(MediaType.parse
22                 ("application/octet-stream"), file);
23 
24         Request request = new Request.Builder()
25                 .url(url)
26                 .post(fileBody)
27                 .build();
28 
29         Call call = okHttpClient.newCall(request);
30 
31         //[1]同步请求;
32        /* try {
33             call.execute();
34         } catch (IOException e) {
35             e.printStackTrace();
36         }*/
37 
38         //[2]异步请求
39         call.enqueue(new Callback() {
40             @Override
41             public void onFailure(Call call, IOException e) {
42 
43             }
44 
45             @Override
46             public void onResponse(Call call, Response response) throws IOException {
47 
48             }
49         });
50     }

【progressRequestBody类的实现】

 1 package com.oztaking.www.a02_okhttp.okHttpUtils;
 2 
 3 import java.io.IOException;
 4 
 5 import okhttp3.MediaType;
 6 import okhttp3.RequestBody;
 7 import okhttp3.ResponseBody;
 8 import okio.Buffer;
 9 import okio.BufferedSink;
10 import okio.ForwardingSink;
11 import okio.Okio;
12 import okio.Sink;
13 
14 
15 /**
16  * [8]文件的上传增加进度
17  * 对于上传的进度的处理会比较麻烦,因为具体的上传过程是在RequestBody中由OkHttp帮我们处理上传,
18  * 而且OkHttp并没有给我们提供上传进度的接口,这里做法是自定义类继承RequestBody,
19  * 然后重写其中的方法,将其中的上传进度通过接口回调暴露出来供使用
20  * 实质:在原有的RequestBody上包装了一层,最后在我们的使用中在post()方法中传入我们的CountingRequestBody对象即可
21  */
22 
23 public class progressRequestBody extends RequestBody {
24 
25     //实际要使用的requestBody
26     private ResponseBody mDelegate;
27     //回调监听
28     private okHttpUpLoadProgressListener mListener;
29     private CountingSink countingSink;
30 
31     public progressRequestBody(ResponseBody mDelegate, okHttpUpLoadProgressListener mListener) {
32         this.mDelegate = mDelegate;
33         this.mListener = mListener;
34     }
35 
36     @Override
37     public MediaType contentType() {
38         return mDelegate.contentType();
39     }
40 
41     /* 返回文件总的字节大小
42      * 如果文件大小获取失败则返回-1*/
43     @Override
44     public long contentLength() {
45         return mDelegate.contentLength();
46     }
47 
48     @Override
49     public void writeTo(BufferedSink sink) throws IOException {
50         countingSink = new CountingSink(sink);
51         //将CountingSink转化为BufferedSink供writeTo()使用
52         BufferedSink bufferedSink = Okio.buffer(countingSink);
53         bufferedSink.flush();
54     }
55 
56 
57     protected final class CountingSink extends ForwardingSink {
58 
59         private long byteWritten;
60 
61         public CountingSink(Sink delegate) {
62             super(delegate);
63         }
64 
65         /**
66          * **
67          * 上传时调用该方法,在其中调用回调函数将上传进度暴露出去,
68          * 该方法提供了缓冲区的自己大小
69          * @param source
70          * @param byteCount
71          * @throws IOException
72          */
73 
74         @Override
75         public void write(Buffer source, long byteCount) throws IOException {
76             super.write(source, byteCount);
77             byteWritten += byteCount;
78             mListener.onRequestProgress(byteWritten,contentLength());
79         }
80     }
81 
82 
83     public static interface okHttpUpLoadProgressListener {
84         /**
85          * 暴露出上传进度
86          *
87          * @param byteWritten   已经上传的字节大小
88          * @param contentLength 文件的总字节大小
89          */
90         void onRequestProgress(long byteWritten, long contentLength);
91     }
92 }

11.同步get

 1 /**
 2      * [9] 同步get
 3      * 下载一个文件,打印他的响应头,以string形式打印响应体。
 4      * 响应体的 string() 方法对于小文档来说十分方便、高效。但是如果响应体太大(超过1MB),应避免适应
 5      * string() 方法 ,因为他会将把整个文档加载到内存中。
 6      * 对于超过1MB的响应body,应使用流的方式来处理body。
 7      */
 8     private void okHttpGetSyncHeader(String url) throws IOException {
 9 
10         OkHttpClient okHttpClient = new OkHttpClient();
11         Request request = new Request.Builder()
12                 .url(url)
13                 .build();
14 
15         Call call = okHttpClient.newCall(request);
16         //同步请求;
17         Response response = call.execute();
18         if (!response.isSuccessful()) {
19             throw new IOException("response error" + response);
20         }
21         //获取到response的头部;
22         Headers responseHeaders = response.headers();
23         int len = responseHeaders.size();
24         for (int i = 0; i < len; i++) {
25             //response的头部的每个信息
26             System.out.println(responseHeaders.name(i) + ":" + responseHeaders.value(i));
27         }
28         //打印头部的所有信息;
29         System.out.println(response.body().string());
30     }

12.异步get

 1  /**
 2      * [10]异步get
 3      *
 4      * @param url
 5      */
 6     private void okHttpGetASyncHeader(String url) {
 7         OkHttpClient okHttpClient = new OkHttpClient();
 8         Request request = new Request.Builder()
 9                 .url(url)
10                 .get()
11                 .build();
12         Call call = okHttpClient.newCall(request);
13         call.enqueue(new Callback() {
14             @Override
15             public void onFailure(Call call, IOException e) {
16 
17             }
18 
19             @Override
20             public void onResponse(Call call, Response response) throws IOException {
21                 if (!response.isSuccessful()) {
22                     throw new IOException("Unexpected code " + response);
23                 }
24                 //获取到response的头部;
25                 Headers headers = response.headers();
26                 int len = headers.size();
27                 for (int i = 0; i < len; i++) {
28                     //response的头部的每个信息
29                     System.out.println("responseHeaders:" + headers.name(i) + ":" + headers.value
30                             (i));
31                 }
32                 //打印头部的所有信息;
33                 System.out.println(response.body().string());
34             }
35         });
36     }

13.提取响应头

 1 /**
 2      * [11] 提取响应头
 3      * 典型的HTTP头 像是一个 Map<String, String> :每个字段都有一个或没有值。
 4      * 但是一些头允许多个值,像Guava的Multimap。
 5      * 例如:HTTP响应里面提供的 Vary 响应头,就是多值的。OkHttp的api试图让这些情况都适用。
 6      * 【header(name, value)】 可以设置唯一的name、value。
 7      * 如果已经有值,旧的将被移除,然后添加新的。
 8      * 【addHeader(name, value)】 可以添加多值(添加,不移除已有的)。
 9      * 当读取响应头时,使用 header(name) 返回最后出现的name、value。
10      * 通常情况这也是唯一的name、value。
11      * 如果没有值,那么 header(name) 将返回null。
12      * 如果想读取字段对应的所有值,使用 headers(name) 会返回一个list(如上例)。
13      * 为了获取所有的Header,Headers类支持按index访问。
14      */
15 
16     private void addHeaders(String url) {
17         OkHttpClient okHttpClient = new OkHttpClient();
18 
19         Request request = new Request.Builder()
20                 .url(url)
21                 .header("User-Agent", "OkHttp Headers.java")
22                 .addHeader("Accept", "application/json:q=0.5")
23                 .addHeader("Accept", "application/vnd.github.v3+json")
24                 .build();
25 
26         Call call = okHttpClient.newCall(request);
27         call.enqueue(new Callback() {
28             @Override
29             public void onFailure(Call call, IOException e) {
30 
31             }
32 
33             @Override
34             public void onResponse(Call call, Response response) throws IOException {
35                 System.out.println(response.header("Server"));
36                 System.out.println(response.header("Date"));
37                 System.out.println(response.headers("Vary"));
38             }
39         });
40     }

14.post 提交String

 1 /**
 2      * [11]post 提交String
 3      * 提交了一个markdown文档到web服务,以HTML方式渲染markdown。
 4      * 因为整个请求体都在内存中,因此避免使用此api提交大文档(大于1MB)。
 5      */
 6 
 7     private void okHttpPostString(String url) {
 8         MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
 9         OkHttpClient okHttpClient = new OkHttpClient();
10         String postBody = ""
11                 + "Releases\n"
12                 + "--------\n"
13                 + "\n"
14                 + " * _1.0_ May 6, 2013\n"
15                 + " * _1.1_ June 15, 2013\n"
16                 + " * _1.2_ August 11, 2013\n";
17 
18         //创建请求体
19         RequestBody requestBody = RequestBody.create(mediaType, postBody);
20 
21         Request request = new Request.Builder()
22                 .url(url)
23                 .post(requestBody)
24                 .build();
25 
26         Call call = okHttpClient.newCall(request);
27         call.enqueue(new Callback() {
28             @Override
29             public void onFailure(Call call, IOException e) {
30 
31             }
32 
33             @Override
34             public void onResponse(Call call, Response response) throws IOException {
35                 if (!response.isSuccessful())
36                     throw new IOException("Unexpected code " + response);
37                 System.out.println(response.body().string());
38             }
39         });
40 
41     }

15.post 方式提交流

 1 /**
 2      * [12]post 方式提交流
 3      * <p>
 4      * 以流的方式POST提交请求体。请求体的内容由流写入产生。
 5      * 这个例子是流直接写入Okio的BufferedSink。
 6      * 你的程序可能会使用 OutputStream ,你可以使用 BufferedSink.outputStream()来获取
 7      */
 8 
 9     private void okHttpPostStream(String url) {
10 
11         final MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
12 
13         OkHttpClient okHttpClient = new OkHttpClient();
14 
15         RequestBody requestBody = new RequestBody() {
16             @Override
17             public MediaType contentType() {
18                 return mediaType;
19             }
20 
21             @Override
22             public void writeTo(BufferedSink sink) throws IOException {
23                 /**
24                  * 关键的方法:sink.writeUtf8
25                  */
26                 sink.writeUtf8("Numbers\n");
27                 for (int i = 2; i <= 997; i++) {
28                     sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
29                 }
30             }
31 
32             private String factor(int n) {
33                 for (int i = 2; i < n; i++) {
34                     int x = n / i;
35                     if (x * i == n) return factor(x) + " × " + i;
36                 }
37                 return Integer.toString(n);
38             }
39         };
40 
41         Request request = new Request.Builder()
42                 .url(url)
43                 .post(requestBody)
44                 .build();
45         Call call = okHttpClient.newCall(request);
46         call.enqueue(new Callback() {
47             @Override
48             public void onFailure(Call call, IOException e) {
49 
50             }
51 
52             @Override
53             public void onResponse(Call call, Response response) throws IOException {
54                 if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
55                 System.out.println(response.body().string());
56             }
57         });
58     }

16.响应缓存

 1 /**
 2      * [13]响应缓存----没有弄明白;
 3      * 【注意】Okhttp仅支持get请求缓存,其他请求方式需要自己实现 
 4      *
 5      * 缓存响应:需要建立可以读写的缓存目录和限定缓存大小。
 6      * 建立的缓存目录应该是私有的,不信任的程序应不能读取缓存内容。
 7      * 一个缓存目录不能同时拥有多个缓存访问。
 8      * 大多数程序只需要调用一次 new OkHttp() ,在第一次调用时配置好缓存,然后其他使用到的地方只需要调用这个实例。
 9      * 否则两个缓存示例互相干扰,破坏响应缓存,而且有可能会导致程序崩溃。
10      * 响应缓存使用HTTP头作为配置。
11      * 你可以在请求头中添加 Cache-Control: max-stale=3600 ,OkHttp缓存会支持。
12      * 你的服务通过响应头确定响应缓存多长时间,例如使用 Cache-Control: max-age=9600
13      */
14 
15     private void okHttCacheResponse(File cacheDirector) {
16 
17         //使用OkHttp的Cache,首先需要指定缓存的路径和大小
18         int cacheSize = 10 * 1024 * 1024;
19         Cache cache = new Cache(cacheDirector, cacheSize);
20 
21         OkHttpClient okHttpClient
22                 = new OkHttpClient()
23                 .newBuilder()
24                 .cache(cache)
25                 .build();
26 
27         Request request = new Request.Builder()
28                 .url("http://publicobject.com/helloworld.txt")
29                 .build();
30 
31         Call call1 = okHttpClient.newCall(request);
32         call1.enqueue(new Callback() {
33             @Override
34             public void onFailure(Call call, IOException e) {
35 
36             }
37 
38             @Override
39             public void onResponse(Call call, Response response1) throws IOException {
40                 if (!response1.isSuccessful())
41                     throw new IOException("Unexpected code " + response1);
42 
43                 String s = response1.body().string();
44                 Logger.d("response1:"+s);
45                 Logger.d("response1 Cache response:"+response1.cacheResponse());
46                 Logger.d("response1 network response:"+response1.networkResponse());
47             }
48         });
49 
50         Call call2 = okHttpClient.newCall(request);
51         call2.enqueue(new Callback() {
52             @Override
53             public void onFailure(Call call, IOException e) {
54 
55             }
56 
57             @Override
58             public void onResponse(Call call, Response response2) throws IOException {
59                 if (!response2.isSuccessful())
60                     throw new IOException("Unexpected code " + response2);
61 
62                 String s = response2.body().string();
63                 Logger.d("response2:"+s);
64                 Logger.d("response2 Cache response:"+response2.cacheResponse());
65                 Logger.d("response2 network response:"+response2.networkResponse());
66             }
67         });
68 
69 //        System.out.println("Response 2 equals Response 1? " +
70 //                response2.equals(response1));
71     }

17.取消一个Call

 1 /**
 2      * [14]取消一个Call--没有弄明白;
 3      *
 4      * 使用 Call.cancel() 可以立即停止掉一个正在执行的call。
 5      * 如果一个线程正在写请求或者读响应,将会引发IOException 。
 6      * 当call没有必要的时候,使用这个api可以节约网络资源。
 7      * 例如当用户离开一个应用时。不管同步还是异步的call都可以取消。
 8      * 你可以通过tags来同时取消多个请求。
 9      * 当你构建一请求时,使用 RequestBuilder.tag(tag) 来分配一个标签。
10      * 之后你就可以用 OkHttpClient.cancel(tag) 来取消所有带有这个tag的call
11      */
12     private void okHttpCancelCall(){
13 
14         ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
15         OkHttpClient okHttpClient = new OkHttpClient();
16 
17         Request request = new Request.Builder()
18                 .url("http://httpbin.org/delay/2")// This URL is served with a 2 second delay.
19                 .tag(1)
20                 .build();
21 
22         final long nanoTime = System.nanoTime();
23         final Call call = okHttpClient.newCall(request);
24 
25         // Schedule a job to cancel the call in 1 second.
26         executor.schedule(new Runnable() {
27             @Override
28             public void run() {
29                 System.out.printf("%.2f Canceling +++++ call.%n",(System.nanoTime() - nanoTime) / 1e9f);
30                 call.cancel();
31                 System.out.printf("%.2f Canceled ------call.%n", (System.nanoTime() - nanoTime) / 1e9f);
32             }
33         },1, TimeUnit.SECONDS);
34 
35         System.out.printf("%.2f Canceling #### call.%n",(System.nanoTime() - nanoTime) / 1e9f);
36         call.enqueue(new Callback() {
37             @Override
38             public void onFailure(Call call, IOException e) {
39 
40             }
41 
42             @Override
43             public void onResponse(Call call, Response response) throws IOException {
44                 System.out.printf("%.2f Call was  $$$$$ bexpected to fail, but completed: %s%n",
45                         (System.nanoTime() - nanoTime) / 1e9f, response);
46             }
47         });
48 
49 
50     }

18.设置超时时间

 1 /**
 2      * [15]超时
 3      * 没有响应时使用超时结束call。
 4      * 没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西。
 5      * OkHttp支持连接,读取和写入超时。
 6      */
 7 
 8     private void okHttpTimeout(){
 9         OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
10                 .connectTimeout(1,TimeUnit.SECONDS)
11                 .readTimeout(1,TimeUnit.SECONDS)
12                 .writeTimeout(1,TimeUnit.SECONDS)
13                 .pingInterval(10,TimeUnit.SECONDS) //websocket 轮训间隔
14                 .build();
15 
16         Request request = new Request.Builder()
17                 .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
18                 .build();
19 
20         Call call = okHttpClient.newCall(request);
21         call.enqueue(new Callback() {
22             @Override
23             public void onFailure(Call call, IOException e) {
24 
25             }
26 
27             @Override
28             public void onResponse(Call call, Response response) throws IOException {
29                 System.out.println("Response completed: " + response.body().string());
30             }
31         });
32     }

19.配置call

 1 /**
 2      * [16]每个call的配置--clone
 3      * 使用 OkHttpClient ,所有的HTTP Client配置包括代理设置、超时设置、缓存设置。当你需要为单个call改变
 4      * 配置的时候,clone 一个 OkHttpClient 。这个api将会返回一个浅拷贝(shallow copy),你可以用来单独自
 5      * 定义。下面的例子中,我们让一个请求是500ms的超时、另一个是3000ms的超时。
 6      */
 7 
 8 
 9   /*  public void run() throws Exception {
10         final OkHttpClient client = new OkHttpClient();
11         Request request = new Request.Builder()
12                 .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
13                 .build();
14         try {
15             Response response = client.clone() // Clone to make a customized OkHttp for this
16             request..setReadTimeout(500, TimeUnit.MILLISECONDS)
17                     .newCall(request)
18                     .execute();
19             System.out.println("Response 1 succeeded: " + response);
20         } catch (IOException e) {
21             System.out.println("Response 1 failed: " + e);
22         }
23         try {
24             Response response = client.clone() // Clone to make a customized OkHttp for this
25             request..setReadTimeout(3000, TimeUnit.MILLISECONDS)
26                     .newCall(request)
27                     .execute();
28             System.out.println("Response 2 succeeded: " + response);
29         } catch (IOException e) {
30             System.out.println("Response 2 failed: " + e);
31         }
32     }*/
33 
34 
35     private void OkHttpCallConfigure(){
36         OkHttpClient okHttpClient = new OkHttpClient();
37         Request request = new Request.Builder()
38                 .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay
39                 .build();
40 
41         Call call = okHttpClient.newCall(request);
42         Call clone = call.clone();
43 
44     }

20.Cookie 保存

 1 /**
 2      * [17]Cookie 保存
 3      * Request经常都要携带Cookie,上面说过request创建时可以通过header设置参数,Cookie也是参数之一
 4      * 然后可以从返回的response里得到新的Cookie,可能得想办法把Cookie保存起来。
 5      * 但是OkHttp可以不用我们管理Cookie,自动携带,保存和更新Cookie。
 6      * 方法是在创建OkHttpClient设置管理Cookie的CookieJar
 7      *
 8      */
 9     private void OkHttpCookieSave(String url){
10 
11         final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
12 
13         OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
14                 .cookieJar(new CookieJar() {
15                     @Override
16                     public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
17                         // 保存cookie通常使用SharedPreferences
18                         cookieStore.put(url.host(), cookies);
19                     }
20 
21                     @Override
22                     public List<Cookie> loadForRequest(HttpUrl url) {
23                         // 从保存位置读取,注意此处不能为空,否则会导致空指针
24                         List<Cookie> cookies = cookieStore.get(url.host());
25                         return cookies != null ? cookies : new ArrayList<Cookie>();
26 
27                     }
28                 })
29                 .build();
30 
31         Request request = new Request.Builder()
32                 .url(url)
33                 .header("Cookie", "xxx") //添加cookie;
34               .build();
35     }

21.添加拦截器

 1 /**
 2      * [21]添加拦截器
 3      * okHttp3的实现使用的是链式的拦截器,同时也开放了自定义拦截器接口
 4      */
 6     private void okHttpAddInterceptor(){
 7         new OkHttpClient.Builder()
 8                 // 此种拦截器将会在请求开始的时候调用
 9                 .addInterceptor(new Interceptor() {
10                     @Override
11                     public Response intercept(Chain chain) throws IOException {
12                         return null;
13                     }
14                 })
15                 // 连接成功,读写数据前调用
16                 .addNetworkInterceptor(new Interceptor() {
17                     @Override
18                     public Response intercept(Chain chain) throws IOException {
19                         return null;
20                     }
21                 }).build();
22     }

22.https的支持

 1  /**
 2      *  [22]https的支持添加
 3      *  okhttp3完全支持https,设置证书即可
 4      *  未完成,报错;
 5      */
 6     private void okHttpHttps(){
 7         OkHttpClient okHttpClient = new OkHttpClient.Builder()
 8                 .sslSocketFactory(SSLSocketFactory(), X509TrustManager)
 9                 .build();
10     }

23.Websocket支持

 1     /**
 2      * [23]Websocket支持
 3      * okhttp3支持websocket,简易推送,轮训都可以使用
 4      * websocket协议首先会发起http请求,握手成功后,转换协议保持长连接,类似心跳
 5      *
 6      * 【说明】创建一个OkHttpClient,通常是单例,
 7      *  如果要自定义一些属性那就要用内部的Builder来构造
 8      *
 9      *  [参考文章]https://blog.csdn.net/xlh1191860939/article/details/75452342/
10      */
11 
12     private void okHttpWebSocket(String url){
13         OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
14         Request request = new Request.Builder()
15                 .url(url)
16                 .build();
17         okHttpClient.newWebSocket(request, new WebSocketListener() {
18             @Override
19             public void onOpen(WebSocket webSocket, Response response) {
20                 super.onOpen(webSocket, response);
21                 // 连接成功
22             }
23 
24             @Override
25             public void onMessage(WebSocket webSocket, String text) {
26                 super.onMessage(webSocket, text);
27                 // 当收到文本消息
28             }
29 
30             @Override
31             public void onMessage(WebSocket webSocket, ByteString bytes) {
32                 super.onMessage(webSocket, bytes);
33                 // 收到字节消息,可转换为文本
34             }
35 
36             @Override
37             public void onClosing(WebSocket webSocket, int code, String reason) {
38                 super.onClosing(webSocket, code, reason);
39 
40             }
41 
42             @Override
43             public void onClosed(WebSocket webSocket, int code, String reason) {
44                 super.onClosed(webSocket, code, reason);
45                 // 连接被关闭
46             }
47 
48             @Override
49             public void onFailure(WebSocket webSocket, Throwable t, Response response) {
50                 super.onFailure(webSocket, t, response);
51                 // 连接失败
52             }
53         });
54     }

24.混淆

1 在混淆文件(proguard-rules.pro)中添加如下语句:
2 -dontwarn okhttp3.**

 【参考文章】

【1】https://www.jianshu.com/p/9aa969dd1b4d

【2】http://www.cnblogs.com/ct2011/p/3997368.html
【3】https://www.jianshu.com/p/1873287eed87



 

 

 

 1 /**
 2      * [3]post http文件上传
 3      * 最主要的还是创建合适的RequestBody
 4      */
 5     private void okHttpPostFile(String url) {
 6 
 7         OkHttpClient okHttpClient = new OkHttpClient();
 8 
 9         //读取外部的sd卡的文件上传;
10         File file = new File(Environment.getExternalStorageDirectory(), "mimi.mp4");
       //关键是requestBody的构造
11 RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"),file); 13 14 Request request = new Request.Builder() 15 .url(url) 16 .post(fileBody) 17 .build(); 18 19 Call call = okHttpClient.newCall(request); 20 21 //[1]同步请求; 22 /* try { 23 call.execute(); 24 } catch (IOException e) { 25 e.printStackTrace(); 26 }*/ 27 28 //[2]异步请求 29 call.enqueue(new Callback() { 30 @Override 31 public void onFailure(Call call, IOException e) { 32 33 } 34 35 @Override 36 public void onResponse(Call call, Response response) throws IOException { 37 38 } 39 }); 40 }

 

 

 

 

 

 

 

 

5.Post方式提交分块请求

 1 /**
 2      * [4-2] Post方式提交分块请求
 3      * MultipartBuilder 可以构建复杂的请求体,与HTML文件上传形式兼容。
 4      * 多块请求体中每块请求都是一个请求体,可以定义自己的请求头。
 5      * 这些请求头可以用来描述这块请求,例如他的 Content-Disposition 。
 6      * 如果 Content-Length 和 Content-Type 可用的话,他们会被自动添加到请求头中
 7      *
 8      * @param url
 9      * @throws Exception 【注意】上面的描述是基于okhttp2.0;代码是基于okhttp3.0;
10      */
11     private void okHttpPostBlockData(String url) throws Exception {
12 
13         final String IMGUR_CLIENT_ID = "...";
14         final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
15         OkHttpClient client = new OkHttpClient();
16 
17         MultipartBody multipartBody = new MultipartBody.Builder()
18                 .setType((MultipartBody.FORM))
19                 .addPart(Headers.of("Content-Disposition", "form-data; name=\"title\""),
20                         RequestBody.create(null, "Square Logo"))
21                 .addPart(Headers.of("Content-Disposition", "form-data; name=\"image\""),
22                         RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square" +
23                                 ".png")))
24                 .build();
25 
26         Request request = new Request.Builder()
27                 .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
28                 .url("")
29                 .post(multipartBody)
30                 .build();
31 
32         Response response = client.newCall(request).execute();
33         if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
34         System.out.println(response.body().string());
35     }
posted @ 2018-06-29 10:00  OzTaking  阅读(1866)  评论(0)    收藏  举报