Retrofit的使用

Retrofit也是Square公司的一個開源庫裆站,主要是對Http網絡請求框架的封裝搏恤,其本質上還是由OkHttp(默認)完成具體的網絡請求梢莽,Retrofit只是對網絡請求接口進行了封裝(把每一個API網絡請求都變成一個Java接口)嗓袱。
具體流程如下:


具體流程圖
  • App應用程序通過 Retrofit 請求網絡,實際上是使用 Retrofit 接口層封裝請求參數胸蛛、Header污茵、Url 等信息,之后由 OkHttp 完成后續(xù)的請求操作
  • 在服務端返回數據之后葬项,OkHttp 將原始的結果交給 Retrofit泞当,Retrofit根據用戶的需求對結果進行解析

使用Retrofit的步驟:
1.添加Retrofit庫的依賴,添加網絡請求權限
2.創(chuàng)建接收服務器返回數據的類(JavaBean)
3.創(chuàng)建用于描述網絡請求的接口

  • Retrofit把每一個http請求抽象成了Java接口,通過注解來描述請求方式和請求參數民珍,還可以通過注解來配置網絡請求參數 襟士。
  • 內部的實現原理就是通過動態(tài)代理將接口的注解翻譯成一個個http請求,再有線程池來執(zhí)行這一個個的網絡請求嚷量。

4.創(chuàng)建Retrofit實例(Builder構造者模式)
5.創(chuàng)建網絡請求接口的實例
6.發(fā)送網絡請求(異步enqueue/同步execute)
7.處理服務器返回的數據

PS: 這里具體說一下第三點陋桂,創(chuàng)建網絡請求的接口時用到了大量的注解處理,包括請求頭津肛、請求方式章喉、請求參數等等。

注解詳情:
1.網絡請求方式的注解:

網絡請求方式

這里注意一下@HTTP的使用:

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.GET;
import retrofit2.http.HTTP;
import retrofit2.http.Path;

public interface ServiceApi {

    /**
     * method:網絡請求的方法(區(qū)分大小寫)
     * path:網絡請求地址路徑
     * hasBody:是否有請求體
     */
    @HTTP(method = "GET", path = "xxx/{id}", hasBody = false)
    Call<ResponseBody> getCall(@Path("id") int id);
    // {id} 表示是一個變量
    // method 的值 retrofit 不會做處理身坐,所以要自行保證準確

}
  • 作用:替換@GET、@POST落包、@PUT部蛇、@DELETE、@HEAD等注解的作用及更多功能拓展
  • 具體使用:通過屬性method咐蝇、path涯鲁、hasBody進行設置

2.標記具體作用的注解:


標記具體作用的注解

a. @FormUrlEncoded
作用:表示發(fā)送form-encoded的數據

每個鍵值對需要用@Filed來注解鍵名,隨后的對象需要提供值有序。

b. @Multipart
作用:表示發(fā)送form-encoded的數據(適用于 有文件 上傳的場景)

每個鍵值對需要用@Part來注解鍵名抹腿,隨后的對象需要提供值。

 /**
     * 表明是一個表單格式的請求(Content-Type:application/x-www-form-urlencoded)
     * Field("username") 表示將后面的 String name 中name的取值作為 username 的值
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrl(@Field("username") String name, @Field("password") int pwd);

    /**
     * Part 后面支持三種類型旭寿,RequestBody警绩、okHttp3.MultipartBody.Part 、任意類型
     * 除 okHttp3.MultipartBody.Part 以外盅称,其它類型都必須帶上表單字段(okHttp3.MultipartBody.Part 中已經包含了表單字段的信息)肩祥,
     */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpLoad(@Part("name") RequestBody name, @Part("password") RequestBody pwd, @Part MultipartBody.Part file);

具體使用:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ServiceApi service = retrofit.create(ServiceApi.class);
        // @FormUrlEncoded 
        Call<ResponseBody> call = service.testFormUrl("Jack", 123456);

        // @Multipart
        MediaType textType = MediaType.parse("text/plain"); // 文本類型
        RequestBody name = RequestBody.create(textType, "Jack");
        RequestBody pwd = RequestBody.create(textType, "123456");
        RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "這里是模擬文件的內容");

        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
//        Call<ResponseBody> call = service.testFileUpLoad(name, pwd, filePart);

        //發(fā)送網絡請求(異步)
        call.enqueue(new Callback<ResponseBody>() {
            //請求成功時回調
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                //請求處理,輸出結果
                assert response.body() != null;
                response.body().toString();
            }

            //請求失敗時候的回調
            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
                System.out.println("連接失敗");
            }
        });

3.網絡請求參數的注解:

網絡請求參數的注解

詳解:
1.@Header 和 @Headers
作用:添加不固定的請求頭 和 添加請求頭
具體使用如下:

// @Header 使用
    @GET("xxx")
    Call<Test> getTest(@Header("Authorization") String authorization);

    // @Headers 使用
    @Headers("Authorization: authorization")
    @GET("xxx")
    Call<Test> getTest();

// 以上的效果是一致的后室。
// 區(qū)別在于使用場景和使用方式
// 1. 使用場景:@Header用于添加不固定的請求頭,@Headers用于添加固定的請求頭
// 2. 使用方式:@Header作用于方法的參數混狠;@Headers作用于方法

2.@Body:
作用:以 Post方式 傳遞 自定義數據類型 給 服務器(Server)
特別注意:如果提交的是一個Map岸霹,那么作用相當于 @Field
不過Map要經過 FormBody.Builder 類處理成為符合 OkHttp 格式的表單,如下:

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

3.@Field 和 @FieldMap:
作用:發(fā)送 Post請求時提交請求的表單字段
具體使用:與 @FormUrlEncoded 注解配合使用

/**
     * 表明是一個表單格式的請求(Content-Type:application/x-www-form-urlencoded)
     * Field("username") 表示將后面的 String name 中name的取值作為 username 的值
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrl(@Field("username") String name, @Field("password") int pwd);

    /**
     * Map的key作為表單的鍵
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrl(@FieldMap Map<String, Object> map);

調用:

        // @Field
        Call<ResponseBody> call = service.testFormUrl("Jack", 123456);

        // @FieldMap
        // 實現的效果與上面相同将饺,但要傳入Map
        Map<String, Object> map = new HashMap<>();
        map.put("username", "Jack");
        map.put("password", 123456);
        Call<ResponseBody> call = service.testFormUrl(map);

        //發(fā)送網絡請求(異步)
        call.enqueue(new Callback<ResponseBody>() {
            //請求成功時回調
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                //請求處理,輸出結果
                assert response.body() != null;
                response.body().toString();
            }

            //請求失敗時候的回調
            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
                System.out.println("連接失敗");
            }
        });

4.@Part & @PartMap:
作用:發(fā)送 Post請求 時提交請求的表單字段

  • 與@Field的區(qū)別:功能相同贡避,但攜帶的參數類型更加豐富,包括數據流予弧,所以適用于 有文件上傳 的場景
  • 具體使用:與 @Multipart 注解配合使用:
/**
     * Part 后面支持三種類型刮吧,RequestBody、okHttp3.MultipartBody.Part 桌肴、任意類型
     * 除 okHttp3.MultipartBody.Part 以外皇筛,其它類型都必須帶上表單字段(okHttp3.MultipartBody.Part 中已經包含了表單字段的信息),
     */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpLoad(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);

    /**
     * PartMap 注解支持一個Map作為參數坠七,支持 RequestBody 類型水醋,
     * 如果有其它的類型,會被retrofit2.Converter轉換彪置,如后面會介紹的 使用Gson的 retrofit2.converter.gson.GsonRequestBodyConverter
     * 文件只能用 @Part MultipartBody.Part 
     */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpLoad(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);

    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpLoad(@PartMap Map<String, RequestBody> args);

調用:

MediaType textType = MediaType.parse("text/plain");
        RequestBody name = RequestBody.create(textType, "Jack");
        RequestBody pwd = RequestBody.create(textType, "123456");
        RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "這里是模擬文件的內容");

        // @Part
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
        Call<ResponseBody> call = service.testFileUpLoad(name, pwd, filePart);

        // @PartMap
        // 實現和上面同樣的效果
        Map<String, RequestBody> mapParam = new HashMap<>();
        mapParam.put("name", name);
        mapParam.put("password", pwd);
        //這里并不會被當成文件拄踪,因為沒有文件名(包含在Content-Disposition請求頭中),但上面的 filePart 有
        //mapParam.put("file", file);
        Call<ResponseBody> call = service.testFileUpLoad(mapParam, filePart); //單獨處理文件

        //發(fā)送網絡請求(異步)
        call.enqueue(new Callback<ResponseBody>() {
            //請求成功時回調
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                //請求處理,輸出結果
                assert response.body() != null;
                response.body().toString();
            }

            //請求失敗時候的回調
            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
                System.out.println("連接失敗");
            }
        });

5.@Query和@QueryMap:

  • 作用:用于 @GET 方法的查詢參數(Query = Url 中 ‘?’ 后面的 key-value)

如:url = http://www.platfrom.net/?type=android其中拳魁,Query = type

  • 具體使用:
@GET("xxx/")
    Call<String> tag(@Query("type") String type);

    @GET("xxx/")
    Call<String> tag(@QueryMap Map<String, Object> args);

調用:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.xxx.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ServiceApi service = retrofit.create(ServiceApi.class);
        // @Query
        Call<String> call = service.tag("android");

        // @QueryMap
        // 實現的效果與上面相同惶桐,但要傳入Map
        Map<String, Object> map = new HashMap<>();
        map.put("type", "android");
        Call<String> call = service.tag(map);

        //發(fā)送網絡請求(異步)
        call.enqueue(new Callback<String>() {
            //請求成功時回調
            @Override
            public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                //請求處理,輸出結果
                assert response.body() != null;
                response.body().toString();
            }

            //請求失敗時候的回調
            @Override
            public void onFailure(@NonNull Call<String> call, @NonNull Throwable throwable) {
                System.out.println("連接失敗");
            }
        });

6.@Path:
作用:URL地址的缺省值
具體使用:

@GET("xxx/{yyy}/zzz")
    Call<ResponseBody>  getGitHub(@Path("yyy") String yyy);
    // 訪問的API是:https://api.github.com/xxx/{yyy}/zzz
    // 在發(fā)起請求時, {yyy} 會被替換為方法的第一個參數 yyy(被@Path注解作用)

7.@Url:
作用:直接傳入一個請求的 URL變量 用于URL設置
具體使用:

@GET
        Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
       // 當有URL注解時潘懊,@GET傳入的URL就可以省略
       // 當GET姚糊、POST...HTTP等方法中沒有設置Url時,則必須使用 @Url

總結:

注解總結

以上注解知識摘自網上及自己的一些總結授舟,這里做記錄純屬為了以后查閱方便救恨。

下面創(chuàng)建一個完整的例子來走一遍Retrofit的網絡請求:

1.添加Retrofit庫的依賴,添加網絡請求權限:

"com.squareup.retrofit2:retrofit:2.5.0",
"com.squareup.retrofit2:converter-gson:2.5.0",
"com.squareup.retrofit2:adapter-rxjava:2.5.0",
"com.squareup.retrofit2:converter-scalars:2.0.1",
"com.squareup.okhttp3:okhttp:3.12.1",
"com.squareup.okhttp3:logging-interceptor:3.10.0",
<uses-permission android:name="android.permission.INTERNET"/>

2.創(chuàng)建接收服務器返回數據的類(JavaBean)

public class WorksListVo {
    public WorksItem data;

    public class WorksItem {
        public ArrayList<Works> content;
    }

    public static class Works {
        public String tid;
        public String hits;
        public String utime;
        public String f_catalog_id;
        public String uid;
        public String content;
        public String province;
        public String avatar;
        public String sname;
        public String genderid;
        public String gender;
        public String intro;
    }
}

3.創(chuàng)建用于描述網絡請求的接口

public interface ApiService {

    @POST("/xxx/thread/yyy")
    @FormUrlEncoded
    Call<WorksListVo> getWorkMoreData(@Field("last_id") String last_id,     
    @Field("utime") String utime, @Field("rn") String rn);
}

4.創(chuàng)建Retrofit實例(Builder構造者模式)

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.xxx.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

5.創(chuàng)建網絡請求接口的實例

ApiService service = retrofit.create(ApiService.class);
Call<WorksListVo> call = service.getWorkMoreData("9526","2019-01-11",android");

6.發(fā)送網絡請求(異步enqueue/同步execute)
7.處理服務器返回的數據(通過response類的 body()對返回的數據進行處理)

//發(fā)送網絡請求(異步)
        call.enqueue(new Callback<String>() {
            //請求成功時回調
            @Override
            public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                //請求處理,輸出結果
                assert response.body() != null;
                response.body().toString();
            }

            //請求失敗時候的回調
            @Override
            public void onFailure(@NonNull Call<String> call, @NonNull Throwable throwable) {
                System.out.println("連接失敗");
            }
        });

Retrofit源碼解讀傳送門:http://www.reibang.com/p/cef4cfc4f756

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末释树,一起剝皮案震驚了整個濱河市肠槽,隨后出現的幾起案子,更是在濱河造成了極大的恐慌奢啥,老刑警劉巖秸仙,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異桩盲,居然都是意外死亡寂纪,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門正驻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弊攘,“玉大人抢腐,你說我怎么就攤上這事〗蠼唬” “怎么了迈倍?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捣域。 經常有香客問我啼染,道長,這世上最難降的妖魔是什么焕梅? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任迹鹅,我火速辦了婚禮,結果婚禮上贞言,老公的妹妹穿的比我還像新娘斜棚。我一直安慰自己,他們只是感情好该窗,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布弟蚀。 她就那樣靜靜地躺著,像睡著了一般酗失。 火紅的嫁衣襯著肌膚如雪义钉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天规肴,我揣著相機與錄音捶闸,去河邊找鬼。 笑死拖刃,一個胖子當著我的面吹牛删壮,可吹牛的內容都是我干的。 我是一名探鬼主播兑牡,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼醉锅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了发绢?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤垄琐,失蹤者是張志新(化名)和其女友劉穎边酒,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體狸窘,經...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡墩朦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了翻擒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氓涣。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡牛哺,死狀恐怖,靈堂內的尸體忽然破棺而出劳吠,到底是詐尸還是另有隱情引润,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布痒玩,位于F島的核電站淳附,受9級特大地震影響,放射性物質發(fā)生泄漏蠢古。R本人自食惡果不足惜奴曙,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望草讶。 院中可真熱鬧洽糟,春花似錦、人聲如沸堕战。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽践啄。三九已至浇雹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屿讽,已是汗流浹背昭灵。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伐谈,地道東北人烂完。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像诵棵,于是被迫代替她去往敵國和親抠蚣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內容