Retrofit2 學習總結(jié)

原文鏈接:
http://www.reibang.com/p/a8b88c7fe831
http://blog.csdn.net/qq_24889075/article/details/52181133

概述

在學習 Retrofit2 的過程中受到了一些阻力,現(xiàn) Retrofit2 學會使用了,特此寫此文驗證所學知識。同時也希望幫助和我一樣在學習Retrofit2遇到困難的猿們先煎。

當我在剛開始學習 Retrofit2 的時候并不知道Retrofit2是什么東西,后來逐漸了解 “它可能是一個方便我們網(wǎng)絡(luò)請求的庫 诅妹,可以幫我們讓請求網(wǎng)絡(luò)變得更靈活郎汪、易于維護”森瘪。然后還可以和時下比較火熱的RxJava進行完美融合刹帕。

先看看如何使用吵血,如何進行一個簡單的Get/Post請求

Retrofit2 入門

首先在build.gradle中添加如下代碼,添加Retrofit2庫

compile 'com.squareup.retrofit2:retrofit:2.1.0'

有的教程里寫要手動添加okhttp的庫轩拨,其實是不需要的践瓷,因為retrofit2封裝了okhttp,不信自己編譯下看看:


gradle
External libraries

添加完庫院喜,我們開始正文亡蓉。

我們在項目中進行網(wǎng)絡(luò)請求時,肯定不是一個地址吧喷舀,那么這些請求地址存放在哪呢砍濒?是在哪個類里請求就在哪個類里存放,還是統(tǒng)一放在一個專門存地址的類中呢硫麻?
我在學習Android期間就是哪里有請求就放哪里爸邢,后來有人告訴我要集中存放。于是后來就建立一個AppURL.java所有地址都存放這里拿愧。
然而Retrofit2這里也可以這么理解:專門有一個‘地方’來存儲鏈接地址(也可以創(chuàng)建多個‘地方’存儲)杠河。這個‘地方’不是類而是接口,在這個接口中可以設(shè)定請求地址的一些信息浇辜。就像這樣:

public interface AppURL { 
    @GET("index") 
    Call<ResponseBody> getIndex();
    ...
    ...
//  可以存儲多個連接地址
}

說明:
接口名“AppURL ”可以隨意定義券敌,根據(jù)自己喜好。
第一行:代表get請求,請求地址為“設(shè)定的BaseURL/index” (BaseURL設(shè)定在下面介紹如何設(shè)定)
第二行:getIndex是方法名;Call<ResponseBody>是默認返回類型柳洋,暫且不要管能干什么待诅。

下面我們看下如何使用這些地址進行網(wǎng)絡(luò)請求:

  1. 創(chuàng)建Retrofit對象,并設(shè)定BaseURL
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.這里是BaseURL.com/")
                .build();

需要注意的是BaseURL必須以‘/’結(jié)尾

  1. 獲取“AppURL”對象(創(chuàng)建請求服務)
AppURL url= retrofit.create(AppURL.class);
  1. 用AppURL對象得到具體請求對象(獲取請求服務方法 )
Call<ResponseBody> call = url.getIndex();

后期也會在這一步中進行設(shè)置鏈接參數(shù)熊镣、請求頭等

  1. 開始(異步)請求
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.e("tag", response.body().toString());//獲得數(shù)據(jù)
            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e("tag", t.getMessage());//請求失敗
            }
        });

好了卑雁,現(xiàn)在一個簡單的網(wǎng)絡(luò)請求就寫完了募书。不是很難吧(當時我可是覺得挺難 _

單單會這些是遠遠不夠的,那么我們?nèi)绾蝸頋M足項目中各種各樣的需求呢测蹲?請繼續(xù)看

Retrofit2 進階

自動解析

其實在Retrofit2中莹捡,我們不用自己來解析數(shù)據(jù),Retrofit2可以幫我們自動解析弛房,怎么做呢道盏?請看:

  1. 添加
    在Retrofit2中是用Gson解析的,所以我們要在build.gradle中添加文捶。
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

有寫教程說還有添加gosn庫荷逞,經(jīng)過測試是不需要的,converter-gson中已經(jīng)封裝了gson庫粹排。
需要注意的是converter-gson和retrofit版本號應為一致种远,在這里我都用2.1.0

  1. 創(chuàng)建Bean
    創(chuàng)建一個JavaBean,用于解析服務器返回數(shù)據(jù)顽耳。就和我們平常自己解析創(chuàng)建的Bean一樣坠敷,推薦用As的插件JsonFormat,挺方便的射富。
    我們創(chuàng)建一個Bean起名為MBean.java(隨便起的)
  2. 為retrofit添加addConverterFactory
    添加后的代碼如下:
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.這里是BaseURL.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
  1. 修改泛型
//在AppURL 接口中修改:
@GET("index")
    Call<MBean> getIndex();
 Call<MBean> call = url.getIndex();
//調(diào)用服務請求時的修改
        call.enqueue(new Callback<MBean>() {
            @Override
            public void onResponse(Call<MBean> call, Response<MBean> response) {
                Log.e("tag", response.body().toString());//解析好的數(shù)據(jù)
            }

            @Override
            public void onFailure(Call<MBean> call, Throwable t) {
                Log.e("tag", t.getMessage());
            }
        });

這樣輸出的就直接是用Gson解析好的MBean數(shù)據(jù)了膝迎。

retrofit不僅僅只支持gson,還支持其他許多json解析庫胰耗。 如:
Jackson限次、Moshi、Protobuf柴灯、Wire卖漫、Simple XML、Scalars (primitives, boxed, and String) 具體請看官網(wǎng)

固定地址/路徑替換

說到固定地址了赠群,那么固定地址長什么樣呢羊始?

http://www.BaseURL.com/index
http://www.BaseURL.com/user
http://www.BaseURL.com/login
http://www.BaseURL.com/register/qq
http://www.BaseURL.com/register/wechat

那么應該如何請求呢?除了上面例子中的寫法還可以這樣寫:

    @請求類型("{name}")
    Call<返回類型> 方法名(@path("name") String name);
如:

  @GET("{name}")
    Call<MBean> get(@Path("name") String urlName);

//如果想訪問登錄的鏈接查描,在使用時就直接url.get("login");就可以突委。這樣請求的地址就是http://www.BaseURL.com/login 是不是很方便
//注意@Path和{}中的參數(shù)名要一致

@Path的應該作用暫且理解為 為上面的GET請求傳值

帶參地址

帶參地址長這樣子:

www.BaseURL.com/login?page=1
www.BaseURL.com/movieTop?start=1&count=5
www.BaseURL.com/login?username=testuser&password=123456

上個用的是@Path,這回用的是@Query其實和@Path一樣
直接看例子:

@GET("movieTop")
    Call<MBean> get(@Query("start") int start, @Query("count") int count);
//假設(shè)想查詢電影排行榜的第1-5名冬三,則使用時候是這樣:
Call<MBean> call = url.get(1, 5);
//請求的地址是這樣:www.BaseURL.com/movieTop?start=1&count=5

Post帶Body請求

使用@Body來聲明即可匀油,如下:

 @POST("/aaa")
 Call<MBean> send( @Body UserInfo body);
//使用
Call<MBean> call=url.send();

這里的UserInfo就是要發(fā)送的實體,Retrofit2 會自動轉(zhuǎn)成Gson  

學到這里长豁,一般的網(wǎng)絡(luò)請求都可以了進行钧唐,可以應付一陣子了。
還有一些要求較高的請求匠襟,請看下節(jié)钝侠。

Retrofit2 大成

如果看到這里该园,相信對Retrofit2的基本請求會用了,那么這節(jié)就說一說其他的網(wǎng)絡(luò)請求帅韧。

表單(FormUrlEncoded)

我們可以使用@FormUrlEncoded注解來發(fā)送表單數(shù)據(jù)里初。使用 @Field注解和參數(shù)來指定每個表單項的Key,value為參數(shù)的值忽舟。

@FormUrlEncoded
@POST("user/login")
Call<User> updateUser(@Field("username") String name, @Field("password") String pass);

單文件上傳(Multipart)

 @Multipart
    @POST("register")
    Call<User> registerUser(
      @Part MultipartBody.Part headPhoto, 
      @Part("username") RequestBody userName, 
      @Part("password") RequestBody passWord
  );
//使用
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "二傻子");
RequestBody pass = RequestBody.create(textType, "123456");

RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), 文件對象);
MultipartBody.Part photo = MultipartBody.Part.createFormData("上傳的key", "文件名.png", photoRequestBody);

Call<User> call = url.registerUser(photo,name, pass);

@Part 后面支持三種類型双妨,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 叮阅、任意類型刁品;

動手測試:username的RequestBody 換成String是否可以

多文件上傳

@Multipart
@POST("register")
Call<User> registerUser(@PartMap Map<String, RequestBody> params,  @Part("password") RequestBody password);
//使用
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
Map<String,RequestBody> photos = new HashMap<>();
photos.put("對應的key1"; filename=\"文件名1.png", photo1);
photos.put("對應的key2"; filename=\"文件名2.png", photo2);
photos.put("username",  RequestBody.create(null, "二傻子"));

Call<User> call = userBiz.registerUser(photos, RequestBody.create(null, "123456"));

也可以都塞Map里上傳,也可以只在Map中上傳文件浩姥,隨你嘍~
文章結(jié)尾有參考鏈接挑随。不一樣的上傳方式。

文件和參數(shù)混合上傳

比如修改用戶信息:頭像勒叠、用戶名

    @Multipart
    @POST("地址")
    Call<User> head(@Part("key") RequestBody username,
                              @Part("key\"; filename=\"完整的用戶名") RequestBody img,
                              @Part("key") RequestBody  sex,
                              @Part("key") RequestBody  key
    );
//使用
Call<User> call =url.head(
                RequestBody.create(MediaType.parse("text/plain"),  username),
                RequestBody.create(MediaType.parse("image/*"),  圖片對象),
                RequestBody.create(MediaType.parse("text/plain"),  sex),
                RequestBody.create(MediaType.parse("text/plain"),  key)));

不知道還有沒有其他方法 以后有時間研究下


請求頭

  1. 固定請求頭
     @GET("地址")
     @Headers("Accept-Encoding: application/json")
     Call<返回類型> 方法名();
    // 請求結(jié)果:
    // GET 地址 HTTP/1.1
    // Accept-Encoding: application/json
  1. 動態(tài)請求頭
     @GET("地址")
     Call<返回類型> 方法名(@Header("Location") String location);
    //使用
    url.方法名("參數(shù)");
    // 請求結(jié)果:
    // GET 地址 HTTP/1.1
    // Location: 參數(shù)
  1. 固定+動態(tài)
     @GET("地址")
     @Headers("Accept-Encoding: application/json")
     Call<返回類型> 方法名(@Header("Location") String location);
    //使用
    url.方法名("參數(shù)");
    // 請求結(jié)果:
    // GET 地址 HTTP/1.1
    // Accept-Encoding: application/json
    // Location: 參數(shù)

其他

  1. 注意XXXMap的使用兜挨, 比如@PathMap,@FieldMap等眯分,具體怎么使用拌汇,可以自己研究,研究不出來的可以參考結(jié)尾處的文章弊决。

  2. 下載文件得說說噪舀,在Retrofit2中下載文件是默認存儲到緩存中,也就是說不能進行大的文件下載丢氢,如果要下載大文件要用 @streaming 傅联。但話說回來了先改,下載文件我們可以不用Retrofit2啊疚察,直接用okhttp不就得啦

  3. 我們是可以添加 okhttpclient 到retrofit中去,這樣可以來統(tǒng)一的log管理仇奶,給每個請求添加統(tǒng)一的header等貌嫡,那么我們沒有添加為什么沒有報錯呢? 因為在build()方法中會判斷是否為空该溯,如果我們沒有添加okhttpclient 則就是空了岛抄,那么retrofit會自動給我們添加了一個new OkHttpClient();

  4. execute是同步執(zhí)行 需要在子線程中執(zhí)行、enqueue是異步執(zhí)行狈茉。

  5. 看下我這幾個圖夫椭,整理一下思路吧

HTTP請求方法

以上表格中的除HTTP以外都對應了HTTP標準中的請求方法,而HTTP注解則可以代替以上方法中的任意一個注解,有3個屬性:method氯庆、path蹭秋、hasBody, 這里是用HTTP注解實現(xiàn)的例子

public interface BlogService {
    /**
     * method 表示請的方法扰付,不區(qū)分大小寫
     * path表示路徑
     * hasBody表示是否有請求體
     */
    @HTTP(method = "get", path = "blog/{id}", hasBody = false)
    Call<ResponseBody> getFirstBlog(@Path("id") int id);
}
標記類
參數(shù)類

注1:{占位符}和PATH盡量只用在URL的path部分,url中的參數(shù)使用Query和QueryMap 代替仁讨,保證接口定義的簡潔
注2:Query羽莺、Field和Part這三者都支持數(shù)組和實現(xiàn)了Iterable接口的類型,如List洞豁,Set等盐固,方便向后臺傳遞數(shù)組。

    Call<ResponseBody> foo(@Query("ids[]") List<Integer> ids);
    //結(jié)果:ids[]=0&ids[]=1&ids[]=2

Retrofit2 獨斷萬古

首先說下如何和當前火熱的RxJava進行配合使用丈挟。

  1. 引入RxJava支持 (版本號要一致)
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
  1. 寫接口
@GET(" ^_^ ")
    Observable<MBean> get();
  1. 通過RxJavaCallAdapterFactory為Retrofit添加RxJava支持
Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("http://www.BaseURL.com/")
      .addConverterFactory(GsonConverterFactory.create())//自動通過Gson轉(zhuǎn)josn刁卜,上面有提到
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加RxJava支持
      .build();
  1. 使用
url.get()
        .subscribeOn(Schedulers.io())
        .subscribe(new Subscriber<MBean>() {
            @Override
            public void onCompleted() {
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onNext(MBean mBean) {
            }
        });

根據(jù)需要添加RxAndroid,這個版本號沒有要求曙咽。

剩下的內(nèi)容講的主要是進行自定義 Converter自定義CallAdapter长酗。還有就是源碼的解析
這里可以參考結(jié)尾處的鏈接桐绒,不獻丑了夺脾。

Retrofit2 + RxJava 第一次使用出現(xiàn)的問題

忘記添加

.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

好的Retrofit2 + RxJava Demo參考:
https://github.com/rengwuxian/RxJavaSamples


參考地址

這些是我在學習過程中收集的一些資料,個人感覺還不錯茉继。
本文部分內(nèi)容來自于下面部分文章

鴻洋:http://blog.csdn.net/lmj623565791/article/details/51304204#t1
圖片來源(經(jīng)過作者授權(quán)拿的圖):http://www.reibang.com/p/308f3c54abdd

其他博客:
http://blog.csdn.net/ljd2038/article/details/51046512
http://blog.csdn.net/biezhihua/article/details/49232289
多文件上傳參考:
http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html
http://www.reibang.com/p/acfefb0a204f

https://futurestud.io/blog/retrofit-getting-started-and-android-client

小說看多了咧叭,起的名有些怪。烁竭。菲茬。 見諒啊 _

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市派撕,隨后出現(xiàn)的幾起案子婉弹,更是在濱河造成了極大的恐慌,老刑警劉巖终吼,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镀赌,死亡現(xiàn)場離奇詭異,居然都是意外死亡际跪,警方通過查閱死者的電腦和手機商佛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姆打,“玉大人良姆,你說我怎么就攤上這事♂O罚” “怎么了玛追?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闲延。 經(jīng)常有香客問我痊剖,道長伯复,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任邢笙,我火速辦了婚禮啸如,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氮惯。我一直安慰自己叮雳,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布妇汗。 她就那樣靜靜地躺著帘不,像睡著了一般谎僻。 火紅的嫁衣襯著肌膚如雪套么。 梳的紋絲不亂的頭發(fā)上缩抡,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天胃榕,我揣著相機與錄音,去河邊找鬼梨州。 笑死非剃,一個胖子當著我的面吹牛寥殖,可吹牛的內(nèi)容都是我干的慈参。 我是一名探鬼主播呛牲,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驮配!你這毒婦竟也來了娘扩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤壮锻,失蹤者是張志新(化名)和其女友劉穎琐旁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猜绣,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡灰殴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了途事。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片验懊。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡擅羞,死狀恐怖尸变,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情减俏,我是刑警寧澤召烂,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站娃承,受9級特大地震影響奏夫,放射性物質(zhì)發(fā)生泄漏怕篷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一酗昼、第九天 我趴在偏房一處隱蔽的房頂上張望廊谓。 院中可真熱鬧,春花似錦麻削、人聲如沸蒸痹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叠荠。三九已至,卻和暖如春扫责,著一層夾襖步出監(jiān)牢的瞬間榛鼎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工鳖孤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留者娱,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓苏揣,卻偏偏與公主長得像肺然,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腿准,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,749評論 25 707
  • 本博客為作者原創(chuàng)际起,如需轉(zhuǎn)載請注明原博客出處:WONDER'TWO 0X00 寫在前面 相信做過And...
    一只酸奶牛哇閱讀 4,349評論 9 34
  • 安卓開發(fā)領(lǐng)域中,很多重要的問題都有很好的開源解決方案吐葱,例如Square公司提供網(wǎng)絡(luò)請求 OkHttp , Retr...
    aaron688閱讀 1,905評論 1 20
  • 前段時間看了RxJava街望,發(fā)現(xiàn)跟他一起用的Retrofit,今天就把認識的他們倆個來總結(jié)梳理一下 一弟跑、什么是RxJ...
    毹毹閱讀 667評論 0 5
  • 一張皮薄肉多的餡餅孟辑,就掛在我能看到卻摸不到的天空上哎甲。此時的我,融入進餡餅金色的光芒中饲嗽,躺在扎人的草地上炭玫,瞪著眼,張...
    半朽閱讀 641評論 15 35