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

上一篇文章咱们讲到了OkHttp的一些相应的用法,若是没有看的那就没有看吧!这篇文章是不会用到相应内容的,由于Retrofit是基于OkHttp进行封装的!因此很好的避开的相应的操做!!!就酱紫了。。。html

惯例一张电影图片镇楼!!!此次就用《一辈子一世》来镇楼吧!java

本文知识点

  • Retrofit的简单使用
  • Retrofit注解的含义
  • Retrofit中一些经常使用的操做

重要的事情说三遍,网络权限必定要加,必定要加!!!git

1. Retrofit的简单使用

Retrofit的简单使用记住一下几个步骤github

  1. 建立Retrofit的实例
  2. 定义相应的接口,获取代理对象
  3. 发送请求
  4. 建立请求的回调

其实以上的步骤和OkHttp的差很少,若是你没看上一篇的话,那么就记住上面的话就能够了!!!接下来咱们一步一步实现,其实仍是很简单的!!!json

1.1 建立Retrofit的实例

请求的地址是这个样子滴:api

http://api.jisuapi.com/news/get?channel=头条&start=0&num=10&appkey=274ff62c9225cfa9
复制代码

我反手就是一串代码:浏览器

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://api.jisuapi.com/news/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
复制代码

其实Retrofit是封装了相应的OkHttp,因此写法固然相似了可是有一点值得注意的,这里有个baseUrl的概念,好比说大家公司全部的API的域名都是以http://api.XXX.xxx/开头的,后面有指定的内容进行匹配。那么这个baseUrl就能够这么写!拿上面这个地址为例:baseUrl就是http://api.jisuapi.com/news/注意:这个baseUrl的结尾必定是"\"结尾的! 若是没有这个就会抛出一个IllegalArgumentException异常!切记,切记。。。再说后面的addConverterFactory(GsonConverterFactory.create())这句,其实就是返回json的结构,由于如今通常的服务器都是以json进行传递的。因此这句话必定要加上,不然也会抛出IllegalArgumentException异常。记住就行了。bash

1.2 定义相应的接口,获取代理对象

由于Retrofit中存在大量的注解,全部的代理对象都在相应的接口中完成,因此这个回过后面的讲解重点,多以能够先不用理解相应的含义,后面会详细讲解。服务器

public interface NewsService {
    @GET("get?channel=头条&start=0&num=10&appkey=274ff62c9225cfa9")
    Call<News> getNews();
}
复制代码

简单的说明一下:上面这个接口,表明是一个GET请求,请求成功后返回一个News对象。网络

NewsService newsService = retrofit.create(NewsService.class);
复制代码

而后回去相应的代理对象的代码。

1.3 发送请求

其实这里就是建立一个Call对象,来获取相应的回调!仅此而已。。。

Call<News> news = newsService.getNews();
复制代码

这里面的方法,对应的是顶部接口的那个方法,从而获取一个Call对象。

1.4 建立请求的回调

这里面的回调和OkHttp的回调基本上是同样的,可是比OkHttp的更人性化而已!由于这里直接能够获取到相应的亲求对象,并且无论你调几回都不会有异常。而且回调是同步的!是否是很6。。。

news.enqueue(new Callback<News>() {
        @Override
        public void onResponse(Call<News> call, Response<News> response) {
            Log.e(TAG, "成功的回调: " + response.body());
            News news = response.body();
            Log.e(TAG, "onResponse: " + news.toString());
        }

        @Override
        public void onFailure(Call<News> call, Throwable t) {
            Log.e(TAG, "失败的回调: " + t.toString());
        }
    });
复制代码

以上就是最简单的一个请求了!下面咱们看一下总体代码吧!

/*1.建立Retrofit的实例*/
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://api.jisuapi.com/news/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        /*2.定义相应的接口,获取代理对象*/
        NewsService newsService = retrofit.create(NewsService.class);
        /*3.发送请求*/
        Call<News> news = newsService.getNews();
        /*4.建立请求的回调*/
        news.enqueue(new Callback<News>() {
            @Override
            public void onResponse(Call<News> call, Response<News> response) {
                Log.e(TAG, "成功的回调: " + response.body());
                News news = response.body();
            }

            @Override
            public void onFailure(Call<News> call, Throwable t) {
                Log.e(TAG, "失败的回调: " + t.toString());
            }
        });
复制代码

2. Retrofit注解的含义

其实Retrofit中的注解不少,可是基本上能够分为一下几类:

  1. GET请求相关的注解
  2. POST请求相关的注解
  3. 公共请求的注解

2.1 GET请求相关的注解

在GET请求中无非就是更改中间的参数或者在后面拼接相应的参数而已无非项目中经常使用的就这几种而已!

2.1.1 @Query 和 @QueryMap (用于GET请求添加参数)

这两个注解用在GET请求中的我就不说了!咦,这不是说了吗?其实说简单点就是在后面追加参数的!!!两个的区别呢?@Query能追加一个,@QueryMap能追加多个!剩下的都同样了!!!

拿上面的地址举个例子说明下@Query:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  10:50
     * description : 演示@Query的示例
     */
    @GET("get?channel=头条&start=0&num=10")
    Call<News> getNews(@Query("appkey") String qppKey);
复制代码

和上面的区别主要是我把最后一个参数放到getNews方法中传递了!调用的地方只要修改一个地方就行。

Call<News> news = newsService.getNews("274ff62c9225cfa9");
复制代码

其余的内容彻底不用动,其实结果和上面同样,这里主要是为了演示而已

好再拿上面的地址举个例子说明下@QueryMap:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  10:50
     * description : 演示@QueryMap的示例
     */
    @GET("get?")
    Call<News> getNews(@QueryMap Map<String, String> map);
复制代码

和上面的区别在于我把全部的参数都放到Map中进行传递了!调用的地方修改为这样就能够了!

Map<String, String> map = new HashMap<>();
        //channel = 头条 & start = 0 & num = 10 & appkey = 274f f62c9225cfa9
        map.put("channel", "头条");
        map.put("start", "0");
        map.put("num", "10");
        map.put("appkey", "274ff62c9225cfa9");

Call<News> news = newsService.getNews(map);
复制代码

结果仍是同样的,只是全部参数都经过map集合进行传递,以上方案选择那个看大家需求就能够了!!!

2.1.2 @Path URL的缺省值补充

其实这个很好理解,就是在URL地址中替换相应的路径中的某一段名称,有的URL地址中间有相应“/”分割的内容,path也就是替换这部分的内容;

这回咱们拿一段新的URL演示一下@Path注解的用法:

//原始路径地址:http://api.jisuapi.com/train/station2s?appkey=274ff62c9225cfa9&start=杭州&end=北京&ishigh=0

    /**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  9:47
     * description : 演示@Path注解的示例
     */
    @GET("{path}/station2s?appkey=274ff62c9225cfa9&start=杭州&end=北京")
    Call<StationBean> getTrainStation(@Path("path") String path, @Query("ishigh") String ishigh);
复制代码

请不要看后面的"ishigh"那个传递,由于以前写了一个参数的方法,因此才加上的!主要看path那块的代码。这里path替换的是"train"这个内容,没有什么记住写法就能够了,调用的时候像下面这样写就能够了:

Call<StationBean> train = newsService.getTrainStation("train", "0");
复制代码

有的人会问这个有什么用?其实对于上面这个请求真的没有什么用,怎么说呢?有的Get请求中间这块是一些用户的参数,好比userId什么的,是动态的话。上面的@Path注解就有相应的用处了。若是上面的地址改为http://api.jisuapi.com/uesrId/station2s?appkey=274ff62c9225cfa9&start=杭州&end=北京&ishigh=0userId是根据用户的ID进行更改的,那么就可使用@Path这个注解了。好了剩下的场景本身发觉吧!!!

2.2 POST请求相关的注解

  1. @FormUrlEncoded和@Multipart
  2. @Field和@FieldMap 添加请求参数(与@FormUrlEncoded注解配合使用)
  3. @Part和@PartMap 添加请求参数(与@Multipart注解配合使用)
  4. @Body 封装一个对象

上面最开始演示的是GET请求,对于POST请求小伙伴们仍是不了解,因此这里先给你们演示一下正常的POST请求是怎么弄的!其实其余的代码都不用动,只须要更改相应的接口就能够了,像以下这样:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  11:51
     * description : 演示POST的请求内容
     */
    @FormUrlEncoded
    @POST("train/station2s?")
    Call<StationBean> getPostTrainStation(@FieldMap Map<String, String> map);
复制代码

使用的时候和上面同样传递相应的内容就能够了!!!

2.2.1 @FormUrlEncoded和@Multipart注解

其实这个是和POST请求一块儿做用才有效的注解,怎么理解呢?记得请求的时候有相应的文件上传吧?其实这个东西就是标记你是上传文件,仍是上传表单的;

  • @FormUrlEncoded 纯表单形式(不包含上传文件)
  • @Multipart 表单形式(包含文件上传)

看上面那个案例,POST请求都应该添加@FormUrlEncoded或者@Multipart注解,不然会抛出java.lang.IllegalArgumentException: @FieldMap parameters can only be used with form encoding. 的异常!

记住上面这些东西,下面用到的时候我会详细讲解的

2.2.2 @Field和@FieldMap 添加请求参数

千万要注意上面两个注解要与@FormUrlEncoded注解配合使用!!!发送POST的表单请求。这里注意@Field和@FieldMap只能携带String类型的参数!

@Field的使用和上面@Query的用法是相似的!只是更改一下相应的注解而已可是@FormUrlEncoded别忘记添加!!!

@FieldMap的案例参考上面getPostTrainStation的内容就能够了!!!因此这里就不贴相应的代码了,请原谅我这种懒癌患者。。。

2.2.3 @Part和@PartMap 添加请求参数

千万要注意上面两个注解要与@Multipart注解配合使用!!!发送POST的表单请求。这里要注意于@Field和@FieldMap的区别在于携带的参数类型更加丰富,包括数据流,因此适用于“有文件上传”的场景!上面都说到了@Part和@PartMap有文件上传的功能,因此这里就直接演示一下相应的文件上传,代码以下:

@Multipart
    @POST("/form")
    Call<ResponseBody> testLoadFile(@Part("name") String name, @Part("age") String age, @Part MultipartBody.Part file);
复制代码

使用的时候代码以下:

MediaType textType = MediaType.parse("text/plain");
    RequestBody name = RequestBody.create(textType, "Carson");
    RequestBody age = RequestBody.create(textType, "24");
    RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的路径");
    MultipartBody.Part body = MultipartBody.Part.createFormData("picture", "文件名称", file);
复制代码

这里最值得说明的就是MediaType.parse("application/octet-stream")这个表明上传文件的类型!

参数 说明
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 二进制流数据

参照以上的类型就能够了!!!由于这里不能用公司的地址去尝试,找了半天没有相应上传的地址,因此我放弃了,不过你按照上面的方式处理就能够了,应该不会错的。若是错了你找我,我给你看看!!!

有人会说,我若是要传一堆参数怎么弄?也就是多个key/value的形式,其实你能够这么弄!

@Multipart
    @POST("/form")
    Call<ResponseBody> testLoadFileMore(@FieldMap Map<String, String> map, @Part MultipartBody.Part file);
复制代码

或者

@Multipart
    @POST("/form")
    Call<ResponseBody> testLoadFileMore(@Part Map<String, RequestBody> map, @Part MultipartBody.Part file);
复制代码

怎么选择就看你项目里面的需求了!!!

2.2.4 @Body 封装一个对象

这个注解是用在POST请求的,这一点千万要注意,其实就是把Body中每个属性取出来,以表单的形式传给服务器的!这里传递的对象服务器传递的参数不一样是这样的{"appkey":"274ff62c9225cfa9","end":"北京","ishigh":"0","start":"杭州"}首先你要明确一点,这个@Body是把内容放在body总传递地的!不是经过header传递的!!!

代码是这样的:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  14:57
     * description : 演示@Body注解的使用
     */
    @POST("train/station2s?")
    Call<StationBean> getPostTrainStationBody(@Body BodyBean bodyBean);
复制代码

传递的时候,正常传递就行了!!!

像下面这样:

BodyBean bodyBean = new BodyBean("274ff62c9225cfa9", "杭州", "北京", "0");
    Call<StationBean> postTrainStationBody = newsService.getPostTrainStationBody(bodyBean);
复制代码

注意点:

  1. 不要像POST请求那样设置@FormUrlEncoded不然会抛出@Body parameters cannot be used with form or multi-part encoding. (parameter #1)异常!
  2. 是传递到相应Request的body中,不是经过header传递的,这个必定要明确。不懂的话,问问后台的人员!!!

2.3 一些公共的请求参数

2.3.1 @Header和@Headers

关于这两个注解很好理解,就是添加请求头的,可是@Header添加固定的请求头,@Headers添加的是不固定的请求头

这里就直接贴一段代码就行了,看了你就能懂了

// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
复制代码

若是你问我请求头是什么的话,你能够在Google浏览器中按F12而后给你一张图!

上面这个你要是不理解,找大家后台的去问问,要么就本身学习一下!我怕我讲不懂,由于我不是服务器的。。。

2.3.2 @Url 容许咱们传入一个URL地址(能够实现相应的重定向)

我是这么理解的,其实我不知道这么理解对不对,可是效果是能看见的!!!也就是我能够无论你baseUrl中设置的内容,这里直接更改相应的URL地址!像下面这样:

首先看一下baseUrl的设置

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://api.jisuapi.com/news/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
复制代码

而后咱们在看咱们怎么从新设置相应的地址:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  9:47
     * description : 获取铁路信息的接口
     */
    @GET
    Call<StationBean> getTrainStation(@Url String url);
复制代码

对就是经过@Url这个注解来从新定制相应的注解,因此这里无论你以前的baseUrl什么样都会从这个url中获取地址,来看一下完整的代码:

/**
     * @author : 贺金龙
     * email : 753355530@qq.com
     * create at 2018/9/7  9:48
     * description : Retrofit更改请求网址的演示
     */
    public void retrofitChange(View view) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://api.jisuapi.com/news/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        NewsService newsService = retrofit.create(NewsService.class);
        Call<StationBean> trainStation = newsService.getTrainStation("http://api.jisuapi.com/train/station2s?appkey=274ff62c9225cfa9&start=杭州&end=北京&ishigh=0");
        trainStation.enqueue(new Callback<StationBean>() {
            @Override
            public void onResponse(Call<StationBean> call, Response<StationBean> response) {
                Log.e(TAG, "请求成功的话证实URL地址已经修改了" + response.body().toString());
            }

            @Override
            public void onFailure(Call<StationBean> call, Throwable t) {
                Request request = call.request();
                HttpUrl url = request.url();

                Log.e(TAG, "请求失败的话打印一下URL地址" + url);
                Log.e(TAG, "onFailure: " + t);
            }
        });
    }
复制代码

其实这里无论你baseUrl设置的地址怎么样?最后访问的都是http://api.jisuapi.com/train/station2s?appkey=274ff62c9225cfa9&start=杭州&end=北京&ishigh=0 这个地址!

那么不少人会问这个有什么做用,想一想大家公司正常的网络请求和修改头像的这两个地址同样吗?反正咱们不同,因此才须要这个东西的!!!


基本上使用的时候就这么多问题,可能有些讲解不到的,若是有什么不到位的,及时补充!!!我理解的也有限。有问题留言,咱们一期讨论!!!

github地址奉上

相关文章
相关标签/搜索