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地址奉上

相關文章
相關標籤/搜索