安卓 OKHttp 的使用

本贴最后更新于 1960 天前,其中的信息可能已经事过景迁

一,OKHttp 介绍

okhttp 是一个第三方类库,用于 android 中请求网络。

这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付 Square 公司贡献(该公司还贡献了 Picasso 和 LeakCanary) 。用于替代 HttpUrlConnection 和 Apache HttpClient(android API23 里已移除 HttpClient)。

okhttp 有自己的官网,官网网址:OKHttp 官网

如果想了解原码可以在 github 上下载,地址是:https://github.com/square/okhttp

在 AndroidStudio 中使用不需要下载 jar 包,直接添加依赖即可:
compile ‘com.squareup.okhttp3:okhttp:3.4.1’

下面对以 OKHttp3 来详细介绍 OKHttp 的使用方法。

二,get 请求的使用方法

使用 OKHttp 进行网络请求支持两种方式,一种是同步请求,一种是异步请求。下面分情况进行介绍。

1,get 的同步请求

对于同步请求在请求时需要开启子线程,请求成功后需要跳转到 UI 线程修改 UI。
使用示例如下:

public void getDatasync(){    new Thread(new Runnable() {        @Override        public void run() {            try {                OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象                Request request = new Request.Builder()                        .url("http://www.baidu.com")//请求接口。如果需要传参拼接到接口后面。                        .build();//创建Request 对象                Response response = null;                response = client.newCall(request).execute();//得到Response 对象                if (response.isSuccessful()) {                Log.d("kwwl","response.code()=="+response.code());                Log.d("kwwl","response.message()=="+response.message());                Log.d("kwwl","res=="+response.body().string());                //此时的代码执行在子线程,修改UI的操作请使用handler跳转到UI线程。                }            } catch (Exception e) {                e.printStackTrace();            }        }    }).start();}

此时打印结果如下:
response.code()==200;
response.message()==OK;
res=={“code”:200,”message”:success};

注意事项:
1,Response.code 是 http 响应行中的 code,如果访问成功则返回 200.这个不是服务器设置的,而是 http 协议中自带的。res 中的 code 才是服务器设置的。注意二者的区别。
2,response.body().string()本质是输入流的读操作,所以它还是网络请求的一部分,所以这行代码必须放在子线程。
3,response.body().string()只能调用一次,在第一次时有返回值,第二次再调用时将会返回 null。原因是:response.body().string()的本质是输入流的读操作,必须有服务器的输出流的写操作时客户端的读操作才能得到数据。而服务器的写操作只执行一次,所以客户端的读操作也只能执行一次,第二次将返回 null。

2,get 的异步请求

这种方式不用再次开启子线程,但回调方法是执行在子线程中,所以在更新 UI 时还要跳转到 UI 线程中。
使用示例如下:

private void getDataAsync() {    OkHttpClient client = new OkHttpClient();    Request request = new Request.Builder()            .url("http://www.baidu.com")            .build();    client.newCall(request).enqueue(new Callback() {        @Override        public void onFailure(Call call, IOException e) {        }        @Override        public void onResponse(Call call, Response response) throws IOException {            if(response.isSuccessful()){//回调的方法执行在子线程。                Log.d("kwwl","获取数据成功了");                Log.d("kwwl","response.code()=="+response.code());                Log.d("kwwl","response.body().string()=="+response.body().string());            }        }    });}

异步请求的打印结果与注意事项与同步请求时相同。最大的不同点就是异步请求不需要开启子线程,enqueue 方法会自动将网络请求部分放入子线程中执行。

注意事项:
1,回调接口的 onFailure 方法和 onResponse 执行在子线程。
2,response.body().string()方法也必须放在子线程中。当执行这行代码得到结果后,再跳转到 UI 线程修改 UI。

三,post 请求的使用方法

Post 请求也分同步和异步两种方式,同步与异步的区别和 get 方法类似,所以此时只讲解 post 异步请求的使用方法。
使用示例如下:

private void postDataWithParame() {    OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。    FormBody.Builder formBody = new FormBody.Builder();//创建表单请求体    formBody.add("username","zhangsan");//传递键值对参数    Request request = new Request.Builder()//创建Request 对象。            .url("http://www.baidu.com")            .post(formBody.build())//传递请求体            .build();    client.newCall(request).enqueue(new Callback() {。。。});//回调方法的使用与get异步请求相同,此时略。}

看完代码我们会发现:post 请求中并没有设置请求方式为 POST,回忆在 get 请求中也没有设置请求方式为 GET,那么是怎么区分请求方式的呢?重点是 Request.Builder 类的 post 方法,在 Request.Builder 对象创建最初默认是 get 请求,所以在 get 请求中不需要设置请求方式,当调用 post 方法时把请求方式修改为 POST。所以此时为 POST 请求。

四,POST 请求传递参数的方法总结

在 post 请求使用方法中讲了一种传递参数的方法,就是创建表单请求体对象,然后把表单请求体对象作为 post 方法的参数。post 请求传递参数的方法还有很多种,但都是通过 post 方法传递的。下面我们看一下 Request.Builder 类的 post 方法的声明:

public Builder post(RequestBody body)

由方法的声明可以看出,post 方法接收的参数是 RequestBody 对象,所以只要是 RequestBody 类以及子类对象都可以当作参数进行传递。FormBody 就是 RequestBody 的一个子类对象。

1,使用 FormBody 传递键值对参数

这种方式用来上传 String 类型的键值对
使用示例如下:

private void postDataWithParame() {    OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。    FormBody.Builder formBody = new FormBody.Builder();//创建表单请求体    formBody.add("username","zhangsan");//传递键值对参数    Request request = new Request.Builder()//创建Request 对象。            .url("http://www.baidu.com")            .post(formBody.build())//传递请求体            .build();    client.newCall(request).enqueue(new Callback() {。。。});//此处省略回调方法。}

2,使用 RequestBody 传递 Json 或 File 对象

RequestBody 是抽象类,故不能直接使用,但是他有静态方法 create,使用这个方法可以得到 RequestBody 对象。

这种方式可以上传 Json 对象或 File 对象。
上传 json 对象使用示例如下:

OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。MediaType JSON = MediaType.parse("application/json; charset=utf-8");//数据类型为json格式,String jsonStr = "{\"username\":\"lisi\",\"nickname\":\"李四\"}";//json数据.RequestBody body = RequestBody.create(JSON, josnStr);Request request = new Request.Builder()        .url("http://www.baidu.com")        .post(body)        .build();client.newCall(request).enqueue(new Callback() {。。。});//此处省略回调方法。

上传 File 对象使用示例如下:

OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。MediaType fileType = MediaType.parse("File/*");//数据类型为json格式,File file = new File("path");//file对象.RequestBody body = RequestBody.create(fileType , file );Request request = new Request.Builder()        .url("http://www.baidu.com")        .post(body)        .build();client.newCall(request).enqueue(new Callback() {。。。});//此处省略回调方法。

3,使用 MultipartBody 同时传递键值对参数和 File 对象

这个字面意思是多重的 body。我们知道 FromBody 传递的是字符串型的键值对,RequestBody 传递的是多媒体,那么如果我们想二者都传递怎么办?此时就需要使用 MultipartBody 类。
使用示例如下:

OkHttpClient client = new OkHttpClient();MultipartBody multipartBody =new MultipartBody.Builder()        .setType(MultipartBody.FORM)        .addFormDataPart("groupId",""+groupId)//添加键值对参数        .addFormDataPart("title","title")        .addFormDataPart("file",file.getName(),RequestBody.create(MediaType.parse("file/*"), file))//添加文件        .build();final Request request = new Request.Builder()        .url(URLContant.CHAT_ROOM_SUBJECT_IMAGE)        .post(multipartBody)        .build();client.newCall(request).enqueue(new Callback() {。。。});

4,自定义 RequestBody 实现流的上传

在上面的分析中我们知道,只要是 RequestBody 类以及子类都可以作为 post 方法的参数,下面我们就自定义一个类,继承 RequestBody,实现流的上传。
使用示例如下:
首先创建一个 RequestBody 类的子类对象:

RequestBody body = new RequestBody() {    @Override    public MediaType contentType() {        return null;    }     @Override    public void writeTo(BufferedSink sink) throws IOException {//重写writeTo方法        FileInputStream fio= new FileInputStream(new File("fileName"));        byte[] buffer = new byte[1024*8];        if(fio.read(buffer) != -1){             sink.write(buffer);        }    }};

然后使用 body 对象:

 OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。Request request = new Request.Builder()        .url("http://www.baidu.com")        .post(body)        .build();client.newCall(request).enqueue(new Callback() {。。。});

以上代码的与众不同就是 body 对象,这个 body 对象重写了 write 方法,里面有个 sink 对象。这个是 OKio 包中的输出流,有 write 方法。使用这个方法我们可以实现上传流的功能。

使用 RequestBody 上传文件时,并没有实现断点续传的功能。我可以使用这种方法结合 RandomAccessFile 类实现断点续传的功能。

五,设置请求头

OKHttp 中设置请求头特别简单,在创建 request 对象时调用一个方法即可。
使用示例如下:

Request request = new Request.Builder()                .url("http://www.baidu.com")                .header("User-Agent", "OkHttp Headers.java")                .addHeader("token", "myToken")                .build();

其他部分代码略。

六,下载文件

在 OKHttp 中并没有提供下载文件的功能,但是在 Response 中可以获取流对象,有了流对象我们就可以自己实现文件的下载。代码如下:
这段代码写在回调接口 CallBack 的 onResponse 方法中:

try{    InputStream  is = response.body().byteStream();//从服务器得到输入流对象    long sum = 0;    File dir = new File(mDestFileDir);    if (!dir.exists()){        dir.mkdirs();    }    File file = new File(dir, mdestFileName);//根据目录和文件名得到file对象    FileOutputStream  fos = new FileOutputStream(file);    byte[] buf = new byte[1024*8];    int len = 0;    while ((len = is.read(buf)) != -1){        fos.write(buf, 0, len);    }    fos.flush();    return file; }

七,对于 OKHttp 的使用封装

由于 okhttp 是偏底层的网络请求类库,返回结果的回调方法仍然执行在子线程中,需要自己跳转到 UI 线程,使用麻烦。为了使用方便需要对 OKHttp 进行再次封装。对于 OKHttp 的封装首推的就是 hongyang 大神的 OKHttpUtils。我个人在看过 OKHttp 的原码和借鉴各大神的封装源码后封装了一套自己的 OKHttpUtils。这套 OKHttpUtils 最大的优点是简单和便于使用,这是我项目中实际用的网络请求工具类,完全可以说拿来即用。而且代码简单,可供学习使用。

github 的地址是:https://github.com/guozhengXia/OkHttpUtils

封装的功能有:

  • 一般的 get 请求
  • 一般的 post 请求
  • 上传单个文件(包含进度)
  • 上传 list 集合文件
  • 上传 map 集合文件
  • 文件下载(包含进度)
  • 图片下载(实现了图片的压缩)

请大家多多支持,多多提出宝贵意见

  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 54 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...