当前位置:   article > 正文

OkHttp3简介和使用详解

okhttp3

1 简介

  • OKHttp是一个当前主流的网络请求的开源框架
  • Square公司开发,用于替代HttpUrlConnection和Apache HttpClient
  • Android4.4开始,google已经开始将源码中的HttpURLConnection替换为OkHttp
    Android6.0里已移除HttpClient

优点 (版本一)

  • 支持HTTP2/SPDY(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。)
  • socket自动选择最好路线,并支持自动重连,拥有自动维护的socket连接池,减少握手次数,减少了请求延迟,共享Socket,减少对服务器的请求次数。
  • 基于Headers的缓存策略减少重复的网络请求。
  • 拥有Interceptors轻松处理请求与响应(自动处理GZip压缩)。

优点 (版本二)

1)支持http2,对一台机器的所有请求共享同一个socket
2)内置连接池,支持连接复用,减少延迟
3)支持透明的gzip压缩响应体
4)通过缓存避免重复的请求
5)请求失败时自动重试主机的其他ip,自动重定向
6)好用的API

功能

  • PUT,DELETE,POST,GET等请求
  • 文件的上传下载
  • 加载图片(内部会图片大小自动压缩)
  • 支持请求回调,直接返回对象、对象集合
  • 支持session的保持

2 基本使用

首先记得在build.gradle 和 配置文件分别加上依赖 和 网络权限

  1. compile 'com.squareup.okhttp3:okhttp:3.8.0'
  2. compile 'com.squareup.okio:okio:1.12.0'

<uses-permission android:name="android.permission.INTERNET"/>

2-1 异步Get请求

异步GET请求的4个步骤:

  1. 创建OkHttpClient对象
  2. 通过Builder模式创建Request对象,参数必须有个url参数,可以通过Request.Builder设置更多的参数比如:header、method等
  3. 通过request的对象去构造得到一个Call对象,Call对象有execute()和cancel()等方法。
  4. 以异步的方式去执行请求,调用的是call.enqueue,将call加入调度队列,任务执行完成会在Callback中得到结果。

注意事项:

  • 异步调用的回调函数是在子线程,我们不能在子线程更新UI
    需要借助于 runOnUiThread() 方法或者 Handler 来处理。
  • onResponse回调有一个参数是response
    如果想获得返回的是字符串,可以通过response.body().string()
    如果获得返回的二进制字节数组,则调用response.body().bytes()
    如果想拿到返回的inputStream,则调response.body().byteStream()
    有inputStream我们就可以通过IO的方式写文件

实例:

我新建了一个活动,并在布局里放入一个按钮,点击就会开始执行网络请求

  1. private void getRequest() {
  2. //1.创建OkHttpClient对象
  3. OkHttpClient okHttpClient = new OkHttpClient();
  4. //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
  5. Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
  6. //3.创建一个call对象,参数就是Request请求对象
  7. Call call = okHttpClient.newCall(request);
  8. //4.请求加入调度,重写回调方法
  9. call.enqueue(new Callback() {
  10. //请求失败执行的方法
  11. @Override
  12. public void onFailure(Call call, IOException e) {
  13. }
  14. //请求成功执行的方法
  15. @Override
  16. public void onResponse(Call call, Response response) throws IOException {
  17. String data = response.body().string();
  18. Log.d("response",data);
  19. runOnUiThread(new Runnable() {
  20. @Override
  21. public void run() {
  22. //更新UI
  23. }
  24. });
  25. }
  26. });
  27. }
  • 打个断点可以看到请求成功,返回了一串html的文字

     

2-2 同步Get请求 (较少用)

  • 同步GET请求和异步GET请求基本一样,不同地方是同步请求调用Call的execute()方法,而异步请求调用call.enqueue()方法
  1. //1.创建OkHttpClient对象
  2. OkHttpClient okHttpClient = new OkHttpClient();
  3. //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
  4. Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
  5. //3.创建一个call对象,参数就是Request请求对象
  6. Call call = okHttpClient.newCall(request);
  7. //4.同步调用会阻塞主线程,这边在子线程进行
  8. new Thread(new Runnable() {
  9. @Override
  10. public void run() {
  11. try {
  12. //同步调用,返回Response,会抛出IO异常
  13. Response response = call.execute();
  14. } catch (IOException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }).start();

2-3 异步POST——键值对

  • 通过FormBody
    添加多个String键值对
    最后为Request添加post方法并传入formBody
  • 经过对比我们发现异步的POST请求和GET请求步骤很相似
    这里就不赘述了
  1. private void postAsynHttp() {
  2. mOkHttpClient=new OkHttpClient();
  3. RequestBody formBody = new FormBody.Builder()
  4. .add("size", "10")
  5. .build();
  6. Request request = new Request.Builder()
  7. .url("http://api.1-blog.com/biz/bizserver/article/list.do")
  8. .post(formBody)
  9. .build();
  10. Call call = mOkHttpClient.newCall(request);
  11. call.enqueue(new Callback() {
  12. @Override
  13. public void onFailure(Call call, IOException e) {
  14. }
  15. @Override
  16. public void onResponse(Call call, Response response) throws IOException {
  17. String str = response.body().string();
  18. runOnUiThread(new Runnable() {
  19. @Override
  20. public void run() {
  21. Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
  22. }
  23. });
  24. }
  25. });
  26. }

2-4 异步POST——上传文件

  • 我们需要设置上传类型MIME,我们打算上传一个纯文本
    因此需要用到 MediaType.parse("text/plain; charset=utf-8")
    常见的类型有: 更多参考这里

     

  • 再来看例子

  1. // step 1: 创建 OkHttpClient 对象
  2. OkHttpClient okHttpClient = new OkHttpClient();
  3. //step 2:创建 RequestBody 以及所需的参数
  4. //2.1 获取文件
  5. File file = new File(Environment.getExternalStorageDirectory() + "test.txt");
  6. //2.2 创建 MediaType 设置上传文件类型
  7. MediaType MEDIATYPE = MediaType.parse("text/plain; charset=utf-8");
  8. //2.3 获取请求体
  9. RequestBody requestBody = RequestBody.create(MEDIATYPE, file);
  10. //step 3:创建请求
  11. Request request = new Request.Builder().url("http://www.baidu.com")
  12. .post(requestBody)
  13. .build();
  14. //step 4 建立联系
  15. okHttpClient.newCall(request).enqueue(new Callback() {
  16. @Override
  17. public void onFailure(Call call, IOException e) {
  18. // 请求失败
  19. }
  20. @Override
  21. public void onResponse(Call call, Response response) throws IOException {
  22. // 请求成功
  23. }
  24. });
  • 最后别忘了加文件权限
  1. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2-5 异步Get请求——下载文件

  • 比如下载一张图片,我们得到Response后将流写进我们指定的图片文件中就可以了
  1. private void downAsynFile() {
  2. mOkHttpClient = new OkHttpClient();
  3. String url = "https://img-my.csdn.net/uploads/201603/26/1458988468_5804.jpg";
  4. Request request = new Request.Builder().url(url).build();
  5. mOkHttpClient.newCall(request).enqueue(new Callback() {
  6. @Override
  7. public void onFailure(Call call, IOException e) {
  8. }
  9. @Override
  10. public void onResponse(Call call, Response response) {
  11. InputStream inputStream = response.body().byteStream();
  12. FileOutputStream fileOutputStream = null;
  13. try {
  14. fileOutputStream = new FileOutputStream(new File("/sdcard/123.jpg"));
  15. byte[] buffer = new byte[2048];
  16. int len = 0;
  17. while ((len = inputStream.read(buffer)) != -1) {
  18. fileOutputStream.write(buffer, 0, len);
  19. }
  20. fileOutputStream.flush();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. }
  24. Log.d("123", "文件下载成功");
  25. }
  26. });
  27. }

2-6 异步上传Multipart文件

【待补充】其实这种需求我在实际开发中暂时没有遇到过,也不是很理解

  • 我们在有些情况下既要上传文件还要上传其他类型字段。比如在个人中心我们可以修改名字,年龄,修改图像,这其实就是一个表单。这里我们用到MuiltipartBody ,它 是RequestBody 的一个子类,我们提交表单就是利用这个类来构建一个 RequestBody
  1. //1.创建OkHttpClient对象
  2. OkHttpClient okHttpClient = new OkHttpClient();
  3. //上传的图片
  4. File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
  5. //2.通过new MultipartBody build() 创建requestBody对象,
  6. RequestBody requestBody = new MultipartBody.Builder()
  7. //设置类型是表单
  8. .setType(MultipartBody.FORM)
  9. //添加数据
  10. .addFormDataPart("username","zhangqilu")
  11. .addFormDataPart("age","25")
  12. .addFormDataPart("image","zhangqilu.png",
  13. RequestBody.create(MediaType.parse("image/png"),file))
  14. .build();
  15. //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
  16. Request request = new Request.Builder().url("url").post(requestBody).build();
  17. //4.创建一个call对象,参数就是Request请求对象
  18. Call call = okHttpClient.newCall(request);
  19. //5.请求加入调度,重写回调方法
  20. call.enqueue(new Callback() {
  21. @Override
  22. public void onFailure(Call call, IOException e) {
  23. }
  24. @Override
  25. public void onResponse(Call call, Response response) throws IOException {
  26. }
  27. });

3 其他配置

3-1 设置超时时间和缓存

  • 和OkHttp2.x有区别的是不能通过OkHttpClient直接设置超时时间和缓存了,而是通过OkHttpClient.Builder来设置,通过builder配置好OkHttpClient后用builder.build()来返回OkHttpClient,所以我们通常不会调用new OkHttpClient()来得到OkHttpClient,而是通过builder.build():
  1. File sdcache = getExternalCacheDir();
  2. int cacheSize = 10 * 1024 * 1024;
  3. OkHttpClient.Builder builder = new OkHttpClient.Builder()
  4. .connectTimeout(15, TimeUnit.SECONDS)
  5. .writeTimeout(20, TimeUnit.SECONDS)
  6. .readTimeout(20, TimeUnit.SECONDS)
  7. .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
  8. OkHttpClient mOkHttpClient=builder.build();

3-2 添加请求头

  • 将请求头以键值对形式添加,可添加多个请求头
  1. Request.Builder builder = new Request.Builder().url(url);
  2. builder.addHeader("X-UA","android");

3-3 取消请求

  • 有时候网络条件不好的情况下,用户会主动关闭页面,这时候需要取消正在请求的http request, OkHttp提供了cancel方法,但是实际在使用过程中发现,如果调用cancel()方法,会回调到CallBack里面的 onFailure方法中,
  • 测试发现不同的失败类型返回的IOException e 不一样,所以可以通过e.toString 中的关键字来区分不同的错误类型
  1. 自己主动取消的错误的 java.net.SocketException: Socket closed
  2. 超时的错误是 java.net.SocketTimeoutException
  3. 网络出错的错误是java.net.ConnectException: Failed to connect to xxxxx
  • 因此我们可以做如下处理
  1. call.enqueue(new Callback() {
  2. @Override
  3. public void onFailure(Call call, IOException e) {
  4. if(e.toString().contains("closed")) {
  5. //如果是主动取消的情况下
  6. }else{
  7. //其他情况下
  8. }
  9. }
  • 在okhttp3.Callback的回调方法里面有个参数是Call
    这个call可以单独取消相应的请求,随便在onFailure或者onResponse方法内部执行call.cancel()都可以
    如果想取消所有的请求,则可以okhttpclient.dispatcher().cancelAll();

来源:https://www.jianshu.com/p/16ab28d40737

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/45623
推荐阅读
相关标签
  

闽ICP备14008679号