文章目录

  • 一 、OKHttp简介
  • 二、 OkHttp3使用
  • 1.创建HTTPClient实例
  • 2.Get请求
  • 3.POST请求
  • 三、Timeouts(超时)



**写在前面:本文只是对OKHttp3的简单实用方法介绍,**网络上有很多类似的文章介绍,而且基于OKHttp封装的工具类也有不少,比如:


鸿洋大神的

[Android 一个改善的okHttp封装库]和

[Android OkHttp完全解析 是时候来了解OkHttp了]以及

[Android Https相关完全解析 当OkHttp遇到Https

还有凯子哥的开源项目OkHttpPlus——支持GET、POST、UI线程回调、JSON格式解析、链式调用、文件上传下**

一 、OKHttp简介

OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献(该公司还贡献了Picasso) ,OKHttp用于替代HttpUrlConnection和HttpClient(android API23 6.0里已移除HttpClient,现在代码提示已经画横线了或者直接打不出来)

OkHttp官网地址:https://square.github.io/okhttp/

官网介绍:
OkHttp works on Android 5.0+ (API level 21+) and on Java 8+.
HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.

OkHttp is an HTTP client that’s efficient by default:

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.>

Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks.

功能

  1. get,post请求
  2. 文件的上传下载
  3. 加载图片(内部会图片大小自动压缩)
  4. 支持请求回调,直接返回对象、对象集合
  5. 支持session的保持

二、 OkHttp3使用

(一)添加OkHttp依赖文件和网络访问权限。

Android 接收服务器指令执行相应操作_ide

Android 接收服务器指令执行相应操作_ide_02


添加网络访问权限

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

1.创建HTTPClient实例

简单来说,通过OkHttpClient可以发送一个Http请求,并读取该Http请求的响应,它是一个生产Call的工厂。
此外,受益于一个共享的响应缓存/线程池/复用的连接等因素,绝大多数应用使用一个OkHttpClient实例,便可以满足整个应用的Http请求。

三种创建实例的方法:

// 第一种方法:创建一个默认配置OkHttpClient,可以使用默认的构造函数。

OkHttpClient client = new OkHttpClient();

// 第二种方法:通过new OkHttpClient.Builder()方法来一步一步配置一个OkHttpClient实例。

OkHttpClient clientWith30sTimeout = client.Builder()
    .readTimeout(30, TimeUnit.SECONDS)
    .build();

// 第三种方法: 如果要求使用现有的实例,可以通过newBuilder()方法来进行构造。

OkHttpClient client  = client.newBuilder().build();

2.Get请求

2.1同步GET请求

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Response response = call.execute();
            Log.d(TAG, "run: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

2.2异步GET请求

//1.创建OkHttpClient对象
  OkHttpClient okHttpClient = new OkHttpClient();
  //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
  Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
  //3.创建一个call对象,参数就是Request请求对象
  Call call = okHttpClient.newCall(request);
  //4.请求加入调度,重写回调方法
  call.enqueue(new Callback() {
      //请求失败执行的方法
      @Override
      public void onFailure(Call call, IOException e) {
      }
      //请求成功执行的方法
      @Override
      public void onResponse(Call call, Response response) throws IOException {
      }
  });

注意事项:

  1. 同步GET请求和异步GET请求基本一样,不同地方是同步请求调用Call的execute()方法,而异步请求调用call.enqueue()方法
  2. 异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于 runOnUiThread() 方法或者 Handler 来处理。
  3. 请求成功执行onResponse回调,有一个参数是response
    如果我们想获得返回的是字符串,可以通过response.body().string()获取;
    如果希望获得返回的二进制字节数组,则调用response.body().bytes()
    如果你想拿到返回的inputStream,则调response.body().byteStream(),有inputStream我们就可以通过IO的方式写文件。

2.3异步GET请求下载文件
下载图片、pdf或者音视频等文件是我们经常用到的功能,下载的图片可以保存到本地也可以直接显示在ImageView控件中。

//1.创建OkHttpClient对象
    OkHttpClient okHttpClient = new OkHttpClient();
    //2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
    Request request = new Request.Builder().url("https://www.baidu.com/img/bd_logo1.png").get().build();
    //3.创建一个call对象,参数就是Request请求对象
    Call call = okHttpClient.newCall(request);
    //4.请求加入调度,重写回调方法
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.e(TAG, "onFailure: "+call.toString() );
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            //获取字节流
            InputStream is = response.body().byteStream();
            int len = 0;
            //设置下载图片存储路径和名称
            File file = new File(Environment.getExternalStorageDirectory(),"baidu.png");
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buf = new byte[128];
            while((len = is.read(buf))!= -1){
                fos.write(buf,0,len);
                Log.e(TAG, "onResponse: "+len );
            }
            fos.flush();
            fos.close();
            is.close();
        }
    });

如果把下载的图片显示在ImageView控件中,更改一下第四步中onresponse回调方法即可。

@Override
public void onResponse(Call call, Response response) throws IOException {
    InputStream is = response.body().byteStream();
    //使用 BitmapFactory 的 decodeStream 将图片的输入流直接转换为 Bitmap 
    final Bitmap bitmap = BitmapFactory.decodeStream(is);
    //在主线程中操作UI
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //然后将Bitmap设置到 ImageView 中
            imageView.setImageBitmap(bitmap);
        }
    });
    is.close();
}

3.POST请求

3.1POST请求提交键值对

//1.创建OkHttpClient对象
    OkHttpClient  okHttpClient = new OkHttpClient();
    //2.通过new FormBody()调用build方法,创建一个RequestBody,可以用add添加键值对 
    RequestBody  requestBody = new FormBody.Builder().add("name","zhangqilu").add("age","25").build();
    //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
    Request request = new Request.Builder().url("url").post(requestBody).build();
    //4.创建一个call对象,参数就是Request请求对象
    Call call = okHttpClient.newCall(request);
    //5.请求加入调度,重写回调方法
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {System.out.println(response.body().string());
        }
    });

3.2异步POST请求提交字符串

MediaType mediaType = MediaType.parse("application/json; charset=utf-8");//"类型,字节码"
    //字符串
    String value = "{username:admin;password:admin}"; 
    //1.创建OkHttpClient对象
    OkHttpClient  okHttpClient = new OkHttpClient();
    //2.通过RequestBody.create 创建requestBody对象
    RequestBody requestBody =RequestBody.create(mediaType, value);
    //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
    Request request = new Request.Builder().url("url").post(requestBody).build();
    //4.创建一个call对象,参数就是Request请求对象
    Call call = okHttpClient.newCall(request);
    //5.请求加入调度,重写回调方法
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {System.out.println(response.body().string());
        }
    });

3.3异步POST提交流

public static final MediaType MEDIA_TYPE_MARKDOWN
      = MediaType.parse("text/x-markdown; charset=utf-8");
  private final OkHttpClient client = new OkHttpClient();
  public void run() throws Exception {
    RequestBody requestBody = new RequestBody() {
      @Override public MediaType contentType() {
        return MEDIA_TYPE_MARKDOWN;
      }
      @Override public void writeTo(BufferedSink sink) throws IOException {
        sink.writeUtf8("Numbers\n");
        sink.writeUtf8("-------\n");
        for (int i = 2; i <= 997; i++) {
          sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
        }
      }
      private String factor(int n) {
        for (int i = 2; i < n; i++) {
          int x = n / i;
          if (x * i == n) return factor(x) + " × " + i;
        }
        return Integer.toString(n);
      }
    };
    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();
    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
      System.out.println(response.body().string());
    }
  }

3.4异步POST请求上传文件
我们在注册或者修改信息的时候,需要上传一些图片或者txt、word等文档,所以post提交数据。
首先我们要添加存储卡读写权限,在 AndroidManifest.xml 文件中添加如下代码:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
//1.创建OkHttpClient对象
    OkHttpClient  okHttpClient = new OkHttpClient();
    //上传的图片
    File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
    //2.通过RequestBody.create 创建requestBody对象,application/octet-stream 表示文件是任意二进制数据流
    RequestBody requestBody =RequestBody.create(MediaType.parse("application/octet-stream"), file);
    //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
    Request request = new Request.Builder().url("url").post(requestBody).build();
    //4.创建一个call对象,参数就是Request请求对象
    Call call = okHttpClient.newCall(request);
    //5.请求加入调度,重写回调方法
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {System.out.println(response.body().string());
        }
    });

3.5异步POST提交表单

//1.创建OkHttpClient对象
       OkHttpClient  okHttpClient = new OkHttpClient();
      //2.通过new FormBody build() 创建requestBody对象,
       RequestBody formBody = new FormBody.Builder()
       .add("search", "Jurassic Park")
       .build();
   //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
       Request request = new Request.Builder().url("url").post(requestBody).build();
       //4.创建一个call对象,参数就是Request请求对象
       Call call = okHttpClient.newCall(request);
       //5.请求加入调度,重写回调方法
       call.enqueue(new Callback() {
           @Override
           public void onFailure(Call call, IOException e) {
           }
           @Override
           public void onResponse(Call call, Response response) throws IOException {
           System.out.println(response.body().string());
           }
       });

3.6异步POST提交分块请求
在个人中心我们可以修改名字,年龄,修改图像,这其实就是一个表单,我们提交多种不同类型的数据,需要利用到MuiltipartBody ,它是RequestBody 的一个子类。
MultipartBuilder可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如他的Content-Disposition。如果Content-Length和Content-Type可用的话,他们会被自动添加到请求头中。

//1.创建OkHttpClient对象
        OkHttpClient  okHttpClient = new OkHttpClient();
        //上传的图片
        File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
        //2.通过new MultipartBody build() 创建requestBody对象,
         RequestBody  requestBody = new MultipartBody.Builder()
                //设置类型是表单
                .setType(MultipartBody.FORM)
                //添加数据
                .addFormDataPart("username","zhangqilu")
                .addFormDataPart("age","25")
                .addFormDataPart("image","zhangqilu.png",
RequestBody.create(MediaType.parse("image/png"),file))
                .build();
        //3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
        Request request = new Request.Builder().url("url").post(requestBody).build();
        //4.创建一个call对象,参数就是Request请求对象
        Call call = okHttpClient.newCall(request);
        //5.请求加入调度,重写回调方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

注意事项

如果提交的是表单,一定要设置表单类型, setType(MultipartBody.FORM) 提交文件 addFormDataPart() 方法的第一个参数就是类似于键值对的键,是供服务端使用的,第二个参数是文件的本地的名字,第三个参数是> RequestBody,里面包含了我们要上传的文件的路径以及 MidiaType。

三、Timeouts(超时)

没有响应时使用超时结束call。没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西。OkHttp支持连接,读取和写入超时。

private final OkHttpClient client;
 
  client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build(); 
    Request request = new Request.Builder()
        .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
        .build();

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