Android 網(wǎng)絡請求框架 Retrofit

說一下一年以來使用Retrofit的心得和使用姿勢.

  • Retrofit 是什么:

A type-safe HTTP client for Android and Java

image.png

關于什么是REST ful架構, 這里不詳細說明,其實我也不會詳細說明,簡單來說就是客戶端通過四個HTTP 動詞獲取資源的過程

  • 稍微說明一下HTTP報文的請求組成: 不論是請求報文還是響應報文 headerbody無疑是最重要的兩個部分.請求報文的header中會攜帶 Cookie,Cookie就是服務端來驗證和區(qū)別客戶端的手段,這個客戶端是否是有效登陸的/是否是 成功注冊過得等等. 響應報文中也會攜帶一些Cookie , 一些瀏覽器會使用一些方法儲存和保護和使用這些Cookie . 在Retrofit 和 Okhttp中表現(xiàn)為CookieJar .

  • 什么是Okhttp: Okhttp 也是Retrofit的 開發(fā)公司Square的作品.Retrofit2封裝了Okhttp的 一些東西,使得網(wǎng)絡請求更加的方便快捷.Retrofit 和 Okhttp這兩者是密不可分的.

進入正題:

    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'

基本配置.

發(fā)送一個GET請求總是很簡單的,我使用官網(wǎng)的POST請求為例說明一下.(我稍微修改了一下)

這個邏輯是這樣子的,如果向服務端發(fā)送一個Task的相關信息,服務端就會返回給你這個Task的一些相關的信息.
服務端返回的是JSON數(shù)據(jù)格式
第一步:
首先寫一個接口 里面有這樣的一個函數(shù):

public interface TaskService {  
    @POST("/tasks")
    Call<Task> createTask(@Body Task task);
}

根據(jù)JSON格式 手寫一個這樣的Java 類 叫做Task

public class Task {  
    private long id;
    private String text;

    public Task(long id, String text) {
        this.id = id;
        this.text = text;
    }
}

因為我現(xiàn)在要進行一個POST請求,so:

Task task = new Task(1,"this is a simple task");
//使用Retrofit 的實例創(chuàng)建一個TaskService 的實例
TaskService taskService = retroft.createTask(TaskService.class);
Call<Task> call  = taskService.createTask(task);

接著進行請求并且獲取請求的結(jié)果:

//進行一個異步請求
call.enqueue(.....);
//或者進行一個同步請求
taskService.createTask(task).execute();

好的,以上就是這樣:

但是

握草這些是什么鬼?看完了這一些代碼片段之后一定有這些疑問:

1) @POST? @Body? 而且 @POST()括號里面的是什么?
2) JSON就JSON數(shù)據(jù)好了 直接寫了一個類是什么意思? 我怎么取出數(shù)據(jù)呢?
3) 同步和異步又是什么鬼? 我是否需要 在主線程開一個線程進行網(wǎng)絡請求? 
4) 如果我需要登錄header,我應該放在哪里呢?
5) 這段代碼沒有給出創(chuàng)建一個Retrofit實例的過程,Retrofit應該如何創(chuàng)建呢?
6) 為什么需要在一個接口中寫這個函數(shù)?

來一步步解釋一下(基本操作)

  • 為什么需要在接口中寫一個函數(shù):
    如果自己寫一個函數(shù)來進行網(wǎng)絡請求不就增加了難度,所以借助已經(jīng)創(chuàng)建好了的Retrofit的實例來給出接口的實例來進行網(wǎng)絡請求是最簡潔的.
  • 如何創(chuàng)建一個Retrofit實例:
//interceptor 是 打印網(wǎng)絡請求的log 并且設置log的層級 Level.BODY的層級是比較全面的 
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
 OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(25, TimeUnit.SECONDS)
                .connectTimeout(25, TimeUnit.SECONDS)
                .writeTimeout(25,TimeUnit.SECONDS)
                .addInterceptor(interceptor)
              //  .cookieJar(cookieJar)
                .build();
//Retrofit實例的創(chuàng)建過程使用了建造者模式:
  Retrofit retrofit = new Retrofit.Builder()  
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .baseUrl("https://something.best.com/api/")
                .build();

之前說過Retrofit的基礎是Okhttp所以,構建Retrofit的時候需要傳入一個OkhttpClient的實例 在這個client的實例中可以設置interceptorCookieJar

在創(chuàng)建Retrofit的實例的過程中baseUrl()就是需要請求的url的一部分, Retrofit在請求的過程中會將@POST括號中的部分 拼接在baseUrl的后面形成一個完整的requestUrl.

這里@POST 是Retrofit的特色之一,使用注解來"標注"請求的類型: POST GET等 而@Body表示后面的數(shù)據(jù)不是攜帶完整數(shù)據(jù)的一個類.

接口中的這個函數(shù)的返回值是一個被包括在Call<T>(CallAdapter)這個泛型T所對應的實際類型,這里就是Task 注意:這里請求時上傳的值和返回的類型都是一樣的都是Task,在其他情況可能不一樣.

這里需要注意的是callAdapter可能不止一種,還有對RxJava的支持Observable<T>也是經(jīng)常見到的.

但是返回的數(shù)據(jù)明明是JSON數(shù)據(jù),為什么變成了一個類 ,這里就需要多謝之前配置的依賴converter-gson提供的一個類GsonConverter,這個類將JSON數(shù)據(jù)轉(zhuǎn)化成了一個類

  {
           "city":"北京",
           "size":16800,
          "population":1600
        }

好比這一段json數(shù)據(jù) 如果你使用GsonFormat這個Android Studio 插件的話 就會生成

String city;
int size;
int population;

這三個量分別對應三個數(shù)據(jù).
之后可以使用一些getter() setter()來取出數(shù)據(jù).

在進行數(shù)據(jù)請求的時候也新建一個這樣的類的實例的話,在構造函數(shù)通填入數(shù)據(jù)就可以了(有一種 key-value的感覺對吧!)

但是如果需要的不只是響應的body中的內(nèi)容 還需要響應報文中的其他東西,可以使用Call<ResponseBody>這樣不止返回Body 還有其他內(nèi)容,但是這樣的話就沒有通過converter轉(zhuǎn)化為一個類了; 同理,如果不想管返回類型,可以使用Call<Void>

此外Retrofit還提供了很多其他的注解@Query/ @QueryMap注解可以用于查詢參數(shù)的場景

https://www.google.com/search?q=something&aqs=somethingelse&sourceid=chrome&ie=UTF-8

代碼可以寫成:

@Query("q") String arg1,@Query("ags") String args2, @Query("sourceid") String args3, @Query("id") String args4;

只需要key和查詢參數(shù)的key一一對應就好了
還有@Path注解和其他注解 這里就不一一贅述了

如果使用的是enqueue()函數(shù)的話 進行的是一個異步的操作,可以再回調(diào)函數(shù)中操作UI線程

 Call<ResponseBody> call = mCcnuService.performLibLogin2();
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
                
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

            }
        });

這個是一個同步的操作 注意不要阻塞了主線程

  retrofit2.Response<ResponseBody> responseBody2 = mCcnuService.performSystemLogin().execute();

最后說一下在使用過程中經(jīng)常出現(xiàn)的問題和一些常見的使用場景的解決策略:

1) 需要訪問url A 獲取數(shù)據(jù)之后 在訪問 url B 使用url A 里面拿到的數(shù)據(jù)訪問 url C 獲取最后想要的數(shù)據(jù):

推薦使用Retrofit的同步操作,這樣的話比較符合邏輯上面的順次進行的概念 如果使用異步操作的話可能會造成回調(diào)地獄

image.png
  1. 為什么命名onSuccess執(zhí)行了 但是沒有取出想要的數(shù)據(jù)?

這個情況多半是在Call<T>中 T 類型的變量名 和JSON數(shù)據(jù)中的不一樣. 這很好理解,key-value 如果key錯誤了就不能取出正確的數(shù)據(jù)了.

在使用@Header注解的時候也要注意這個問題 token/Cookie的key也要和后端提供的一樣.使用postman調(diào)試過,拿到JSON數(shù)據(jù)在使用GsonFormat生成會大大避免這個問題

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末录淡,一起剝皮案震驚了整個濱河市桨吊,隨后出現(xiàn)的幾起案子东亦,更是在濱河造成了極大的恐慌梅猿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凡蜻,死亡現(xiàn)場離奇詭異良拼,居然都是意外死亡疮方,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門唁毒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒜茴,“玉大人,你說我怎么就攤上這事浆西》鬯剑” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵近零,是天一觀的道長诺核。 經(jīng)常有香客問我,道長久信,這世上最難降的妖魔是什么窖杀? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮裙士,結(jié)果婚禮上入客,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好桌硫,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布夭咬。 她就那樣靜靜地躺著,像睡著了一般铆隘。 火紅的嫁衣襯著肌膚如雪卓舵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天咖驮,我揣著相機與錄音边器,去河邊找鬼。 笑死托修,一個胖子當著我的面吹牛忘巧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播睦刃,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼砚嘴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了涩拙?” 一聲冷哼從身側(cè)響起际长,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兴泥,沒想到半個月后工育,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡搓彻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年如绸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旭贬。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡怔接,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稀轨,到底是詐尸還是另有隱情扼脐,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布奋刽,位于F島的核電站瓦侮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏杨名。R本人自食惡果不足惜脏榆,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望台谍。 院中可真熱鬧须喂,春花似錦吁断、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至是己,卻和暖如春又兵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卒废。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工沛厨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摔认。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓逆皮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親参袱。 傳聞我的和親對象是個殘疾皇子电谣,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,756評論 25 707
  • 說到目前最火的網(wǎng)絡請求庫,那肯定是的非Retrofit莫屬了抹蚀,如果你還不了解Retrofit如何使用剿牺,如果你想讓自...
    koala_閱讀 11,654評論 8 34
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)环壤,斷路器晒来,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • AndroidStudio使用kotlin入門 導讀 1、創(chuàng)建第一個kotlin項目 2郑现、java代碼自動轉(zhuǎn)換成...
    b77535296c81閱讀 24,463評論 4 9
  • 媒體人在商業(yè)里找到自己的新活法潜索,歡迎你來,我是佳侖懂酱。昨天晚上八點,我和小蝶做了連線誊抛,關于配音和模仿列牺,我們聊了一個多...
    佳侖閱讀 634評論 0 1