美文网首页
OkHttp、rxJava、Retrofit联合网络请求(一)

OkHttp、rxJava、Retrofit联合网络请求(一)

作者: 笔墨Android | 来源:发表于2018-09-06 11:36 被阅读0次

    现在基本上所有的网络框架都采用Okhttp、rxjava、retrofit三者一起写的。因为最近没有什么事情,就抽空总结一下这方面的知识:因为这些东西连在一期讲的话,很多同学会觉得懵逼,所以这里我准备先讲一下每一个东西的用法,然后在讲解一下怎么联合使用。

    最近看了 《X特遣队/自杀小队》 觉得不错。以一种混子的心态生活,其实挺轻松的!所以一张图片镇楼!习惯的我可以发给你!

    image

    本文知识点

    • OkHttp的使用
    • OkHttp上传文件
    • OkHttp的一些高级用法

    1. OkHttp的简单使用

    在这里先来个重要的说明:网络权限一定要加,一定要加!!!

    其实关于OkHttp的使用只要记住一个顺序就可以

    • 创建OkHttpClient对象
    • 创建请求Request内容
    • 发送请求
    • 创建请求的回调

    基本上记住上面的步骤就可以实现简单的请求了!

    1.1 简单的GET请求

    既然上面都提到了相应的步骤,我们就按照上面的步骤写一下就可以了!!!

    1.1.1 创建OkHttpClient对象

    OkHttpClient httpClient = new OkHttpClient();
    

    创建一个对象而已,没有什么好说的!!!

    1.1.2 创建请求Request内容

     Request request = new Request.Builder()
                    .method("GET", null)
                    .url("https://www.baidu.com/")
                    .build();
    

    这里简单说一下,method是设置相应的请求方式的;url是设置相应的请求地址的!其次Request是一个构建者的构建模式。剩下的没有什么好说的。,如果新手,不用管那么多为什么,实现效果才是重要的!!!

    1.1.3 发送请求

    Call call = httpClient.newCall(request);
    

    这里其实就是让httpClient知道自己要请求什么而已

    1.1.4 创建请求返回的内容

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "请求失败的原因:" + e);
            }
    
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                Headers headers = response.headers();
                Set<String> names = headers.names();
                for (String name : names) {
                    Log.e(TAG, "请求的header" + name);
                    String value = headers.get(name);
                    Log.e(TAG, "值为: " + value + "\n----------------------------------");
                }
    
                final String date = response.body().string();
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mTvShow.setText(date);
                    }
                });
            }
        });
    

    这里要说明的就多了:

    1. 当你的看到FATAL EXCEPTION: OkHttp Dispatcher这个异常的时候,恭喜你,你踩到第一个坑了!这个主要是因为response.body().string()只能调用一次,如果你在代码中调用了两次,那么就会出现上面的异常;

    2. 当你异步请求的时候,是不能在子线程修改UI的,所以这里我用了一个Handler去操作相应的内容

    3. 如果你想看相应的一些内容的话,那么看那个for循环那里,你打印一下,就能看到如下的内容,如果不怎么理解的话,找你们后台人员请教一下!一定要虚心哦。

      Accept-Ranges →bytes
      Cache-Control →no-cache
      Connection →Keep-Alive
      Content-Length →227
      Content-Type →text/html
      Date →Wed, 05 Sep 2018 03:41:58 GMT
      Etag →"5b7b7f40-e3"
      Last-Modified →Tue, 21 Aug 2018 02:56:00 GMT
      Pragma →no-cache
      Server →BWS/1.1
      Set-Cookie →BD_NOT_HTTPS=1; path=/; Max-Age=300
      Strict-Transport-Security →max-age=0
      X-Ua-Compatible →IE=Edge,chrome=1
      
    4. 如果失败的话,那么就会在onFailure中把异常反馈给你!!!

    给你贴下整体代码吧!

            /*1.创建OkHttpClient对象*/
            OkHttpClient httpClient = new OkHttpClient();
            /*2.创建请求Request内容*/
            Request request = new Request.Builder()
                    .method("GET", null)
                    .url("https://www.baidu.com/")
                    .build();
            /*3.发送请求*/
            Call call = httpClient.newCall(request);
            /*4.创建请求的回调*/
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "请求失败的原因:" + e);
                }
    
                @Override
                public void onResponse(Call call, final Response response) throws IOException {
                    Headers headers = response.headers();
                    Set<String> names = headers.names();
                    for (String name : names) {
                        Log.e(TAG, "请求的header" + name);
                        String value = headers.get(name);
                        Log.e(TAG, "值为: " + value + "\n----------------------------------");
                    }
    
    
                    final String date = response.body().string();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mTvShow.setText(date);
                        }
                    });
                }
            });
    

    以上步骤就能正常请求相应的数据了,如果还没有数据的话,好好看看代码!

    1.2 简单的POST请求

    关于POST请求的话,基本上就是比GET请求多一步设置表单的方法,也就是一个FormBody对象的设置,以key、value的方式设置表单而已,所以这里教你怎么写,然后我贴一下代码就那么滴了,谁让我那么懒呢!!!

    表单的写法是这样的:

    FormBody formBody = new FormBody.Builder()
                    .add("key", "value")
                    .build();
    

    其实add方法可以被调用多次,添加相应的key和value;

    整体的代码是这样的!!!

            /*1.创建OkHttpClient对象*/
            OkHttpClient httpClient = new OkHttpClient();
            /*2.创建相应的表单内容*/
            FormBody formBody = new FormBody.Builder()
                    .add("key", "value")
                    .build();
            /*3.创建请求Request内容*/
            Request request = new Request.Builder()
                    .url("https://www.baidu.com/")
                    .post(formBody)
                    .build();
            /*4.发送请求*/
            Call call = httpClient.newCall(request);
            /*5.创建请求的回调*/
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "请求失败的原因:" + e);
                }
    
                @Override
                public void onResponse(Call call, final Response response) throws IOException {
                    Headers headers = response.headers();
                    Set<String> names = headers.names();
                    for (String name : names) {
                        Log.e(TAG, "请求的header" + name);
                        String value = headers.get(name);
                        Log.e(TAG, "值为: " + value + "\n----------------------------------");
                    }
    
    
                    final String date = response.body().string();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mTvShow.setText(date);
                        }
                    });
                }
            });
        }
    

    POST和GET请求只是请求的方式不同,POST比较安全,所有内容都依靠表单传递!

    2. OkHttp3进行文件上传

    在这里先来个重要的说明:去写SD卡的权限一定要加,一定要加!!!

    说到文件上传,一般的网络请求都带有文件上传的功能,其实OkHttp3也可以上传文件,具体操作步骤如下:

    • 创建OkHttpClient对象
    • 创建请求Request内容和所有所需参数(这里和其他的请求不同的地方)
      • 获取文件
      • 设置上传文件的类型
      • 获取请求体
    • 创建请求
    • 创建请求的回调

    因为其他的内容都差不多,只有关于表单的内容不通,所以这里着重讲一下关于这个表单的问题。

     RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("title", "张三")
                    .addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png")))
                    .build();
    

    一般这种上传文件,基本上都是传递相应的用户图片,修改图片什么的!因为服务器要根据你上传的这张图片进行相应图片的替换。回来说上面那个配置:

    1. 上面第一个"title"那个参数的话,应该是一组key、value形式,基本上是根据服务器定的参数为准,可以有多组!
    2. 第二个"image"那个参数的话,基本上就是这个形式的key、图片名称、图片位置。这样就能锁定一张图片了,这样就构建出一个相应的RequestBody对象了。

    整体代码是这样的:

            /*1.创建OkHttpClient对象*/
            OkHttpClient httpClient = new OkHttpClient();
            /*2.创建相应的表单内容*/
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("title", "张三")
                    .addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png")))
                    .build();
    
            /*3.创建请求Request内容*/
            Request request = new Request.Builder()
                    .header("key", "value")
                    .url("https://www.baidu.com/")
                    .post(requestBody)
                    .build();
    
            /*4.发送请求*/
            Call call = httpClient.newCall(request);
            /*5.创建请求的回调*/
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(TAG, "onFailure: " + e);
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Log.e(TAG, "onResponse: " + response.body().string());
                }
            });
    

    对了忘说了一点,图片是以流的形式进行传递的。所以上面"application/octet-stream"配置的是这种格式,如果是其他的格式呢?给大家一份对照表:参照一下就OK了。

    参数 说明
    text/html HTML格式
    text/plain 纯文本格式
    text/xml XML格式
    image/gif gif图片格式
    image/jpeg jpg图片格式
    image/png png图片格式
    application/xhtml+xml XHTML格式
    application/xml XML数据格式
    application/atom+xml Atom XML聚合格式
    application/json JSON数据格式
    application/pdf pdf格式
    application/msword Word文档格式
    application/octet-stream 二进制流数据

    基本上你把上面的代码改吧改吧就能上传文件了!!!就酱紫简单。。。

    3. OkHttp的高端配置

    3.1 OkHttp一些基本参数的配置

    配置请求时间和连接超时的时间等等

        OkHttpClient httpClient = new OkHttpClient.Builder()
                //设置相应的连接池
                .connectionPool(new ConnectionPool())
                //连接超时
                .connectTimeout(15, TimeUnit.SECONDS)
                //写入超时
                .writeTimeout(15, TimeUnit.SECONDS)
                //读取超时
                .readTimeout(20, TimeUnit.SECONDS)
                .build();
    

    3.2 OkHttp拦截器的一些简单理解

    往往在项目中,都会有一些关于公共请求参数的一些问题,这里就会用到相应的OkHttp拦截器!什么是拦截器呢?简单点说就和埋点差不多。在请求的时候,会走每一个拦截器!想添加什么就添加什么,这里我们通过几个实例讲解一下你就能大概理解了!

    3.2.1 日志拦截器

    先看下代码,然后我在做一下相应的解释:

    public class LogInterceptor implements Interceptor {
    
        private static final String TAG = LogInterceptor.class.getSimpleName();
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            
            /*这样就能在请求之前打印相应的内容了*/
            Log.e("url", String.format("Sending request %s on %s %n %s", request.url(), chain.connection(), request.headers()));
    
            /*其实下面这个chain.proceed(request)这个方法,代表请求前和请求后*/
            return chain.proceed(request);
        }
    }
    

    这里就是直接打印了一个相应的LOG,可以获取到一些请求的参数,这里说明一下:

    1. 当你的请求为GET请求的时候只能打印一个Url地址,也就是request.url()的值了,饮后后面的headers获取到的内容为空,因为GET请求没有相应的表单信息;
    2. chain.connection()当你使用除了日志拦截器的时候,就会返回空
    3. chain.proceed(request)代表请求响应的结果,所以说明你也是可以修改返回结果的!!!

    3.2.2 重定向一个网址链接的拦截器

    这个说来就有意思了,当你请求拦截器的时候,正常应该返回百度返回的内容,但是如果你修改了链接的地址会怎么样呢?当然就会返回你修改之后的返回地址了。。。我们看看怎么实现的

    public class ResetInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
    
            Request newRequest = new Request.Builder()
                    .method("GET", null)
                    .url("https://fanyi.baidu.com/translate?aldtype=16047&query=%E8%BF%9B%E5%BA%A6%0D%0A&keyfrom=baidu&smartresult=dict&lang=auto2zh#zh/en/%E9%87%8D%E7%BD%AE")
                    .build();
    
            return chain.proceed(newRequest);
        }
    }
    

    对,你没有看错,就这么赤裸裸的换了一个url地址,其实Request request = chain.request();这个方法,返回的Request就是在创建的时候,创建的Request,所以,这里你直接,通过拦截器,直接创建一个新的,直接返回就可以了,就没有之前的Request什么事情了!!!其实就相当于你把之前的内容重新写了一遍!就酱紫了。。。

    3.2.3 添加相应的公共请求参数

    其实这个的实现和上面的差不多,也就是替换相应的Request的内容!但是这里你要考虑一个问题,就是GET请求和POST请求的处理方式应该是不同的,多以这里要分情况去处理。否则不能达到你想要的效果的!所以这里我们分开说。先说明一下,GET请求是在Url后面拼接相应的参数,而POST请求是在form表单中添加相应的参数,所以方式一定是不一样的!!!

    1. GET请求添加公共请求参数

    先来一段代码体验一下:

        HttpUrl build = originalRequest.url().newBuilder()
                .addQueryParameter("key1", "value1")
                .addQueryParameter("key2", "value2")
                .addQueryParameter("key3", "value3")
                .addQueryParameter("key4", "value4")
                .addQueryParameter("key5", "value5")
                .build();
    
        Request request = originalRequest.newBuilder().url(build).build();
    

    这样就可以添加相应的公共请求参数了,其实开始的时候,我以为newBuilder()是创建一个新的内容呢?其实它是拿到之前的内容,然后把下面的内容添加进去。所以这里其他的内容是不会收到影响的!!!

    其实GET请求就是在URL后面追加上相应的参数。

    2. POST请求添加公共请求参数

    还是先来一点代码体验一下:

    Request requestBuilder = originalRequest.newBuilder()
            .addHeader("key1", "value1")
            .addHeader("key2", "value2")
            .addHeader("key3", "value3")
            .addHeader("key4", "value4")
            .addHeader("key5", "value5")
            .build();
    

    和上面的类似,只是写法不同而已!因为POST请求添加的是相应的header。

    整体的代码如下:

    public class PublicInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
    
            Request request = chain.request();
    
            if ("GET".equals(request.method())) {
                //GET请求的处理
                HttpUrl build = request.url().newBuilder()
                        .addQueryParameter("key1", "value1")
                        .addQueryParameter("key2", "value2")
                        .addQueryParameter("key3", "value3")
                        .addQueryParameter("key4", "value4")
                        .addQueryParameter("key5", "value5")
                        .build();
    
                request = request.newBuilder().url(build).build();
            } else if ("POST".equals(request.method())) {
                request = request.newBuilder()
                        .addHeader("key1", "value1")
                        .addHeader("key2", "value2")
                        .addHeader("key3", "value3")
                        .addHeader("key4", "value4")
                        .addHeader("key5", "value5")
                        .build();
            }
    
            return chain.proceed(request);
        }
    }
    

    最后在把相应的Interceptor添加到OkHttp就好了。


    基本上使用的时候就这么多问题,可能有些讲解不到的,如果有什么不到位的,及时补充!!!有问题留言,我看到了一定会回复你的!!!

    github地址奉上

    相关文章

      网友评论

          本文标题:OkHttp、rxJava、Retrofit联合网络请求(一)

          本文链接:https://www.haomeiwen.com/subject/wnatgftx.html