Retrofit之請求參數

在上文,我們了解了如何定義請求Url,感興趣的朋友可以參見《Retrofit之請求Url》。Retrofit系列持續更新,本文介紹如何使用Retrofit定義請求參數。

請求參數從傳遞方式可分三種:url參數,請求主體以及表單編碼。我們來一一討論。

url參數

單個請求參數

url參數就是在url鏈接后面的鍵值對,例如https://api.weibo.com/2//statuses/public_timeline.json?access_token=xxx中,access_token就是url參數,xxx為其值。

Retrofit定義url參數非常直接,只要在方法參數前面添加@Query("key")注解即可。@Query中key的值與url中的參數名稱是一致的,Retrofit會自動添加這些參數到url中。

以之前獲取微博公共動態的API為例,具體API詳見http://open.weibo.com/wiki/2/statuses/public_timeline。從接口中看到,必選參數只有access_token一個,我們定義個方法如下:

@GET("/statuses/public_timeline.json")
Call<Timeline> timelineForPublic(@Query("access_token") String token);

方法timelineForPublic需要參數token,Retrofit會通過@Query中定義的名稱access_token將token映射成請求參數access_token。此時,請求url就會變成:

/statuses/public_timeline.json?access_token=<token>

多個請求參數

從獲取微博公共動態的API中我們可以看到,除了必選的access_token,還有三個可選參數count、page以及base_app,也就是說現在請求參數有四個了。有了上面定義請求參數的介紹,我們只需要往方法上添加相應的參數并用@Query進行注解:

@GET("/statuses/public_timeline.json")
Call<Timeline> timelineForPublic(@Query("access_token") String token, @Query("count") int count, @Query("page") int page, @Query("base_app") int baseApp);

此時,如果我們只需要傳遞access_token,而不需要其他參數,則可以在調用方法的時候傳null。當然,我們不能傳null給int這樣的原生類型,而需要使用對應的Integer。而Retrofit會跳過值為null的參數,并在組裝請求的時候忽略它們。

獲取公共微博最多有四個參數,那么我們再查看下獲取好友微博APIhttp://open.weibo.com/wiki/2/statuses/friends_timeline,發現其有一個必選參數以及七個可選參數,也就是方法會有八個參數。那么問題來了,如果有更多的可選參數,那方法的參數是不是也會特別多,而且很多時候我們只需要其中一兩個請求參數,卻需要提供所有的參數值,顯然很繁瑣。為了處理這種情況,QueryMap就該登場了。

我們可以使用下面的方式定義獲取公共微博API的方法:

@GET("/statuses/public_timeline.json")
Call<Timeline> timelineForPublic(@QueryMap Map<String, String> options);

@QueryMap后面需要緊跟著一個Map< String, String >類型,這樣就可以動態地添加查詢參數了。如果說只需要accept_token參數,則可以像下面這樣調用:

Map<String, String> options = new HashMap<>();
options.put("access_token", AccessTokenKeeper.readAccessToken(getContext()).getToken());
call = weiboService.timelineForPublic(options);

這樣,我們只需要傳遞我們需要設置的參數就可以了。

給每個請求添加url參數

在我們查看微博的各個API時,會發現每個請求都需要一個access_token參數,于是我們就在所有的方法中都添加了對應的參數。那么有沒有簡單的方式來給每個請求都添加相同的參數,從而不需要每個請求都做相同處理呢?

強大的Retrofit是支持的,但是是通過OkHttp中的攔截器來實現的。我們在《Retrofit之初體驗》提及過,Retrofit直接依賴OkHttp,使用OkHttp作為底層網絡客戶端。而使用OkHttp可以添加攔截器,用來修改即將發出去的請求,這個可以參見《OkHttp之攔截器》。這樣我們就可以在攔截器中,對每個請求添加一個access_token參數了:

private static OkHttpClient.Builder okHttpClientBuilder =
        new OkHttpClient.Builder().addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request originalRequest = chain.request();
                HttpUrl originalHttpUrl = originalRequest.url();

                HttpUrl url = originalHttpUrl.newBuilder()
                        .addQueryParameter("access_token", AccessTokenKeeper.readAccessToken(MyApplication.getInstance()).getToken())
                        .build();
                Request request = originalRequest.newBuilder()
                        .url(url)
                        .method(originalRequest.method(), originalRequest.body())
                        .build();

                return chain.proceed(request);
            }
        });

首先獲取到了HttpUrl對象,然后基于原始的HttpUrl對象創建一個新的構建器,從而可以使用addQueryPatameter()方法添加額外的查詢參數,最后將這個新的HttpUrl對象通過Request.Builder方法設置到Request中。

請求主體

在我們實際應用中,大多數時候會通過請求主體向服務器發送數據。以我們的慣例,都會以微博API為例,但可惜的是并沒有找過微博使用這種方式的API,而都使用的是表單方式,這個會在后面討論。所以個很常見的例子,那就是登陸,通常請求參數如下:

{
    "username":"xxx",
    "password":"xxx"
}

好的,登錄的方法定義如下:

@POST("login-path")
Call<User> login(@Body LoginParam param);

其中LoginParam.java類如下:

public class LoginParam {
    private String username;
    private String password;
    public LoginParam(String username, String password) { 
        this.username = username;
        this.password = password;
    }
}

首先,我們使用了@Body注解了方法參數,而我們在創建Retrofit.Builder的時候也為其添加了GsonConverter轉換器。

new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonConverterFactory.create());

這樣,Retrofit會將LoginParam對象轉換為Json,并將其作為主體數據添加到請求中,支持了使用請求主體向服務器發送數據。

表單

在上面我們使用了用請求主體的方式來向服務器發送數據,除了這種方式,還可以通過表單編碼(form-urlencoded)的形式。微博API中的寫入接口都是采用這種方式向服務器發送數據的,我們這里以轉發微博為例,具體API詳見http://open.weibo.com/wiki/2/statuses/repost

首先,定義轉發微博的方法:

@FormUrlEncoded
@POST("statuses/repost.json")
Call<WeiboTimeline> repost(@Field("id") String id);

我們看到了@FormUrlEncoded注解,這個注解不能使用在GET請求上,因為它代表要想服務器發送數據。此外,在參數id上使用@Field注解,表示請求會發送此參數到服務器,而@Field("id")中的id則定義的是參數名稱。

與@Query類似,當你有多個參數要發送時,只需要使用@Field注解它們即可。同樣與@QueryMap對應的有個@FieldMap注解,具體使用類似。

@Field與@FieldMap都有一個屬性encoded,表示鍵值對是否進行url編碼,默認為false。以@Field為例,使用如下:

@FormUrlEncoded
@POST("statuses/repost.json")
Call<WeiboTimeline> repost(@Field(value="id", encoded=true) String id);

了解完@Field之后,我們討論下表單編碼與url參數的區別:表單編碼使用在POST請求中的,而url參數是用在GET請求中的。表單編碼使用請求主體發送數據到服務器,而不是url參數。而url參數的使用主要是為了從服務器過濾或者獲取指定的數據。

Ok,本文就討論到這里,感謝大家的閱讀,下文我們將討論Retrofit如何定義請求頭。

如果你對retrofit感興趣,同時你也覺得我的文章可以給你帶來那么一丟丟的幫助,敬請關注,后續會繼續介紹Retrofit的相關使用。

源碼地址:
https://github.com/FILWAndroid/DevJourney

關于源碼:

  1. 不只是本文涉及的代碼,會包含很多知識點的代碼,應該都會在我的簡書中進行介紹。
  2. 有可能代碼與本文中所貼出來的有差異,但應該都是我覺得更好的方式吧。
  3. 新浪微博相關的代碼運行顯示不出來結果,感興趣的可以參考新浪微博SDK,配置工程。
  4. 歡迎大家對我進行批評教育。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,659評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • 整體Retrofit內容如下: 1、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李頭閱讀 15,116評論 4 39
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評論 6 342
  • “中國人混的就是圈子。” 一個在圈子里小有成就后自己開始創業,目前已融資千萬的Boss對兩個職場小白這樣說道。 引...
    皮皮七閱讀 722評論 2 1