1. 程式人生 > >Retrofit 網路請求

Retrofit 網路請求

宣告本文轉自:http://blog.csdn.net/ghost_programmer/article/details/52372065,如有得罪請聯絡刪除

而Retrofit作為okhttp的升級版,有一個最吸引人的特色就是:將所有的請求封裝為interface,並通過“註解”來宣告api的相關資訊。讓你爽到停不下來。

RESTful API

在正式開始瞭解Retrofit的使用之前,我們有必要先了解一個概念,即RESTful。這是因為Retrofit的初衷就是根據RESTful風格的API來進行封裝的。 
關於RESTful的學習,可以參考一下RESTful API 設計指南

此文。相信看完之後,就會對Restful有一個基本的認識和理解了。 
但我們這裡可以對RESTful的核心思想做一個最簡練的總結,那就是:所謂”資源”,就是網路上的一個實體,或者說是網路上的一個具體資訊。那麼我們訪問API的本質就是與網路上的某個資源進行互動而已。那麼,因為我們實質是訪問資源,所以RESTful設計思想的提出者Fielding認為: 
URI當中不應當出現動詞,因為”資源“表示一種實體,所以應該用名詞表示,而動詞則應該放在HTTP協議當中。那麼舉個最簡單的例子:

  • xxx.com/api/createUser
  • xxx.com/api/getUser
  • xxx.com/api/updateUser
  • xxx.com/api/deleteUser

這樣的API風格我們應該很熟悉,但如果要遵循RESTful的設計思想,那麼它們就應該變為類似下面這樣:

  • [POST]xxx.com/api/User
  • [GET] xxx.com/api/User
  • [PUT]xxx.com/api/User
  • [DELETE]xxx.com/api/User

也就是說:因為這四個API都是訪問伺服器的USER表,所以在RESTful裡URL是相同的,而是通過HTTP不同的RequestMethod來區分增刪改查的行為。 
而有的時候,如果某個API的行為不好用請求方法描述呢?比如說,A向B轉賬500元。那麼,可能會出現如下設計:

POST /accounts/1/transfer/500/to/2

在RESTful的理念裡,如果某些動作是HTTP動詞表示不了的,你就應該把動作做成一種資源。可以像下面這樣使用它:

  POST /transaction HTTP/1.1 
  Host: 127.0.0.1 
   
  from=1&to=2&amount=500.00

好了,當然實際來說RESTful肯定不是就這點內容。這裡我們只是瞭解一下RESTful最基本和核心的設計理念。

從官方介紹初識Retrofit

當我們要去學習一樣新的技術,還有什麼是比官方的資料更好的了呢?所以,第一步我們開啟網址http://square.github.io/retrofit/。然後開始閱讀: 
我們發現官方的介紹非常簡單粗暴,一上來就通過一個Introduction來展示瞭如何使用Retrofit來進行一個最基本的請求。下面我們就逐步的分析一下: 
這裡寫圖片描述 
從上圖中,我們首先注意到了一個關鍵的說明資訊:Retrofit會將你的HTTP API轉換為Java中的interface的形式。OK,接著看: 
這裡寫圖片描述 
這裡我們讀到的描述是:Retrofit類可以針對之前定義的interface生成一個具體實現。我們發現官方對此解釋的很言簡意賅,但更通俗的來講的話: 
也就是說雖然我們之前將此次請求的API資訊封裝為了一個介面,但我們也知道Java中介面是不能產生物件的,這時Retrofit類就站出來扮演了這個角色。 
我們可以將Retrofit類看作是一個“工廠類”的角色,我們在介面中提供了此次的“產品”的生產規格資訊,而Retrofit則通過資訊負責為我們生產。 
這裡寫圖片描述 
這裡我們看到了一個重要的東西“Call”:通過之前封裝的請求介面物件建立的任一的Call都可以發起一個同步(或非同步)的HTTP請求到遠端伺服器。 
之後說了一些通過註解來描述request的好處,然後這個簡單的Introduction就結束了。那麼,現在我們來簡單總結一下,目前為止我們的感受如何。 
我覺得就僅從以上簡單的介紹當中我們起碼有兩點直觀感受:那就是解耦明確使用簡單。通過註解的方式描述request讓人眼前一亮。但與此同時: 
我們發現讀完Introduction後,僅僅是這個基本的用例中,都仍然有很多小細節需要我們通過實際使用之後才能搞明白。這可能在一定程度上說明了: 
為什麼說Retrofit的使用門檻相對於其它庫來說要更高一些。不過沒關係,我們自己先來寫一個比官方Introduction更簡單的用例,再逐步深入。

動手寫第一個Demo來碰坑

現在我們已經閱讀完了官方的用例介紹,乍看之下沒什麼,但實際用起來說不定就得碰坑。為方便測試,仍然通過servlet在本地簡單的實現伺服器。 
我們現在的設想可能是這樣的,我只是想要寫一個demo來測試一下用Retrofit來成功發起一次最基本的get請求,所以最初的doGet無比簡單:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setHeader</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-type"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"text/html;charset=UTF-8"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
        PrintWriter <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span> = response<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getWriter</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.print</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"{\"describe\":\"請求成功\"}"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.flush</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.close</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

完成了以上程式碼的編寫,然後我們把該servlet的URL配置一下,言簡意賅的,就配置為“/api/retrofitTesting”好了。這時伺服器就準備完畢了。 
很顯然,下面我們就可以把焦點放在Android客戶端的實現上來了。為了使用Retrofit,所以我們的第一步工作自然就是在自己的專案中設定依賴

這裡寫圖片描述

配置好了依賴,接著我們就可以開始編碼工作了。還記得官方用例的第一步嗎?所以我們要做的顯然是模仿它也把我們自己的HTTP API封裝成interface。

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> DemoService {
    @GET(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)
    Call<ResponseInfo> testHttpGet();
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// GSON - BEAN</span>
class ResponseInfo {
    String describe;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

現在我們再來看這個所謂的API介面,可能就更加明確一點了。首先是通過註解@GET來宣告本次請求方式為GET以及註明API-URL。 
而就之後宣告的方法來說:從其為Call的返回型別不難猜想多半與請求的發起有關,因為如果我們對OkHttp有所瞭解的話,一定就記得下面這樣的程式碼:

<code class="hljs vbscript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">        OkHttpClient client = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> OkHttpClient();
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Request</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Request</span>.Builder().url(url).build();
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Response</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">response</span> = client.newCall(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">request</span>).<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">execute</span>();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

newCall方法實際就是返回一個Call型別的例項。而Retrofit中的Call介面相對於OkHttp添加了一個泛型,該泛型用於說明本次請求響應的資料解析型別。 
那麼這裡的泛型為什麼是我們自己建立的一個實體類呢?其實回憶一下之前伺服器在response中返回的內容(JSON),就不難猜想到與GSON有關。 
好的,我們繼續按照官方用例中接下來的步驟去完善我們的demo。封裝好了interface,接下來自然就是呼叫了,最終的程式碼如下:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">testRetrofitHttpGet</span>() {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step1</span>
        Retrofit retrofit = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Retrofit.Builder()
                .baseUrl(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://192.168.2.100:8080/TestServer/"</span>)
                .build();
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step2</span>
        DemoService service = retrofit.create(DemoService.class);
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step3</span>
        Call<ResponseInfo> call = service.testHttpGet();
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// step4</span>
        call.enqueue(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Callback<ResponseInfo>() {
            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResponse</span>(Call<ResponseInfo> call, Response<ResponseInfo> response) {
                Log.d(TAG,response.body().describe);
            }

            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onFailure</span>(Call<ResponseInfo> call, Throwable t) {
                Log.d(TAG, t.getMessage());
            }
        });
   }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>

有了之前的說明並對照官方示例,現在會發現以上程式碼很容易理解。而我們發現官方沒有給出的step4其實也很熟悉,因為它和OkHttp的使用是相同的。 
這個時候看上去我們的準備工作就已經完成了,於是興致勃勃的編譯並執行demo來檢視一下效果,卻發現收到了如下的一個異常:

這裡寫圖片描述

為什麼會出現這種情況呢?蛋疼啊!別急,通過異常資訊的描述,我們得知這似乎與型別的轉換相關,然後帶著這個疑問再去檢視官方文件,於是發現:

這裡寫圖片描述

從上述資訊我們得知Retrofit預設只能將響應體轉換為OkHttp中的ResponseBody,而我們之前為Call設定的泛型型別是自定義的型別ResponseInfo 。 
將JSON格式的資料轉換為Java-BEAN,很自然就會想到GSON。而Retrofit如果要執行這種轉換是要依賴於另一個庫的,所以我們還得在專案中配置另一個依賴:

這裡寫圖片描述

之後,在構造Retrofit物件的時候加上一句程式碼就可以了:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">        Retrofit retrofit = new Retrofit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Builder</span>()
                <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.baseUrl</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://192.168.2.100:8080/TestServer/"</span>)
                <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConverterFactory</span>(GsonConverterFactory<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.create</span>()) // 加上這一句哦,親
                <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.build</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

這個時候,當我們再次執行程式就沒問題了,成功的得到如下的日誌列印:

這裡寫圖片描述

現在,經過我們的一番摸索和折騰,關於Retrofit很基本的第一個demo就搗鼓出來了。 
其實這是有意義的,因為回想一下會發現:現在我們對於Retrofit大致的使用套路,在心裡已經有個一二三了。

回到官方文件繼續學習

前面我們說到對於Retrofit的使用已經有了一個基本的認識和了解,接下來要做的自然就是深入和繼續學習更多的使用細節。那麼很顯然,回到官方吧。

這裡寫圖片描述

事實上前面我們已經使用到了註解@GET,這裡就是告訴我們這種註解其實對於HTTP其它常用的請求方式(GET,POST,PUT,DELETE等等)都封裝了。 
而對於@GET來說,我們知道HTTP-GET是可以將一些簡單的引數資訊直接通過URL進行上傳的,所以URL又可以像下面那樣使用:

<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting?param=value"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
  • replacement blocks與@path

不知道大家注意到官方示例和我們剛才自己測試寫的demo中有一個細小的差別沒,就是下面這樣的東西:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//官方的</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"users/{user}/repos"</span>)
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//我們的</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

我們注意到官方的API的URL中有一個”{user}“這樣的東西?它的作用是什麼呢?我們也能在官方文件上找到答案:

這裡寫圖片描述

從上述介紹中,我們注意到一個叫做replacement blocks的東西。可以最簡單的將其理解為路徑替換塊,用”{}”表示,與註解@path配合使用。 
當然我們自己實際去使用一下能夠對其有一個更加深刻的理解,所以我們將我們之前的demo修改一下,變成下面這樣:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/{name}"</span>)
    Call<ResponseInfo> testHttpGet(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Path</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name"</span>) String apiAction);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

使用的方式也會有所不同,我們在呼叫的使用需要將對應的值傳給responseInfo方法。

<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.testHttpGet(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"retrofitTesting"</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

這樣修改過後的實際效果實際上與我們之前的demo是一樣的,那麼這樣做的好處是什麼?顯然是為了解耦。以官方的例子來說: 
“”中的{user}就是為了針對不同的github使用者解耦。因為這裡假設代入我的github,URL就將變成: 
“”。而github的使用者千千萬萬,如果使用我們之前的方式程式碼就會如下:

<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"users/RawnHwang/repos"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

這二者的優劣一目瞭然,我們肯定不會想要為了獲取不同的user的repos去寫N多個套路完全相同的API - interface吧。

  • @Query

前面我們講到:對於@GET來說,引數資訊是可以直接放在url中上傳的。那麼你馬上就反應過來了,這一樣也存在嚴重的耦合!於是,就有了@query。

這裡寫圖片描述

同樣,為了便於理解,我們仍然自己來實際的使用一下。就用我們之前的舉到的例子好了,這裡我們用@query來替換我們之前說到的如下程式碼:

<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting?param=value"</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

替換為:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DemoService</span> {</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@GET</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"api/retrofitTesting"</span>)
    Call<ResponseInfo> testHttpGet(<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Query</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param"</span>) String param);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

呼叫的時候改為:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Call</span><ResponseInfo> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span> = service.testHttpGet(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"value"</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

然後就可以在伺服器檢視是否成功接收到引數了:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">doGet</span>(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(request.getParameter(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"param"</span>));
        }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
  • @QueryMap

聰明的你現在肯定還不滿足,因為可能有這樣的疑問:假設我要在引數中上傳10個引數呢?這意味著我要在方法中宣告10個@Query引數?當然不是!

相關推薦

Retrofit網路請求

本文主要是參考慕課網Jennynick老師視訊所做出的總結。 一、首先明白一點: Retrofit是基於Okhttp網路框架進行的二次封裝,其本質仍是Okhttp。(類似烏爾奇奧拉的二段歸刃) 另外,科普一下,Android5.0之後不再使用HttpClient了。本來還想著看看http

Android中retrofit網路請求框架使用

Retrofit 是 Square 公司出品的 HTTP 請求庫, 同時是 Square 是最早開源專案之一, Retrofit 是目前 Android 最流行的 H

Android——Retrofit網路請求

Retrofit使用步驟 步驟1:新增庫和網路許可權 compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.squareup.retrofit2:converter-gson:2.2.0' compile 'com.

retrofit網路請求引數為json

寫了一段時間的安卓,發現retrofit很好用,註解用法比較簡單,而且整個結構也很清晰。但是使用過程中發生了很多小錯誤,查了一晚上的資料才倒騰明白。 仔細檢查API【敲黑板】 因為沒有好好看api,所以沒有注意傳的引數是json格式的,所以造成了一直報錯的問題。所以要多log看看re

Retrofit網路請求引數註解,@Path、@Query、@Post、Body等總結

Retrofit網路請求引數註解,@Path、@Query、@Post、Body等總結 具體用法參照 Retrofit官網 Retrofit簡介: 是一個基於okhttp的網路請求框架 通過註解配置網路請求引數 圖片連結和圖片上傳 支援同步和非同步網路請

Retrofit網路請求原始碼解析

1.使用者的retrofit建立 /** * 初始化Retrofit */ public static void init() { okHttpClient = HttpsUtils.getOKHttpClient(); //設定Retrofit

Android Retrofit網路請求資料顯示

json解析資料 網路請求許可權 <!--加上網路許可權--> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission a

Retrofit 網路請求框架

1、什麼是Retrofit框架? 它是Square公司開發的現在非常流行的網路框架 2.為什麼使用Retrofit框架         效能好,處理快,使用簡單,Retrofit 是安卓上最流行的HTTP Client庫之一 預設使用OKHttp處理網路請求,我覺

Retrofit網路請求框架中@註解大大大全

註解大全(例項程式碼結合RxJava)   一、方法註解(顧名思義就是針對方法的)     @GET 例項: @POST 例項: @PUT 例項: @DELETE 例項: @PATCH 例項: @HEAD

構建Android專案之RxAndroid+Retrofit網路請求

注意 Retrofit 2.0+和Retrofit 2.0之前的版本語法上有差別,本文基於Retrofit2.1.0 什麼是Retrofit? retrofit是一款針對Android網路請求的開源框架,它與okhttp一樣出自Square公司。Rotrofit2.0的

Retrofit網路請求入門

1、網路請求的原理 在android中所有的網路請求基本上都是相似的 封裝request請求 在請求佇列中執行請求體(網路框架就是在這裡封裝,比如可以使用httpurlconnection,httpclient,okhttp) 執行http請求

Retrofit 網路請求

宣告本文轉自:http://blog.csdn.net/ghost_programmer/article/details/52372065,如有得罪請聯絡刪除 而Retrofit作為okhttp的升級版,有一個最吸引人的特色就是:將所有的請求封裝為int

Android最火框架--Retrofit網路請求庫一

PS:對於Android框架有很多,但一般人都不瞭解,就像網路這一塊,你是不是還在HttpURLConnection,或者HttpClient,這是原始的,而且一般人也都會,這裡我介紹一個網路請求庫,

Retrofit網路請求庫應用01

PS:什麼是Retrofit?   在官方文件中有這樣一句話--A type-safe HTTP client for Android and Java(一個型別安全的http client庫),具體的話就去問百度吧。Retrofit是網路請求庫,是一個開源的。主要是寫程式碼會更少,更快,條例更清晰,剛開始學

關於Retrofit網路請求URL中含有可變引數的處理

       開題:在此預設各位看官對Retrofit、以及Okhttp已經有過一定的瞭解及應用,所以今天我們不談基礎入門的東西,今天我們談在Retrofit請求介面管理類中URL引數含有動態引數的處理方式。一般我們使用Retrofit大部分場景中URL都是以註解的方式靜態宣

Retrofit網路請求封裝公共引數GET和POST請求

public interface ApiService {    /**     * 無參get請求     * http://service.meiyinkeqiu.com/service/ads/cptj     *     * @return     */    //通

Retrofit網路請求,工具類的封裝

對於Retrofit的使用我就不介紹了,使用也不難,隨便去搜兩篇文章看看。 我主要介紹的就是如何封裝,簡便使用。 一、Retrofit工具類的封裝(核心類) /** * Retrofit工具類 */ public class RetrofitUtils {

fastjson的Convert.Factory實現(用fastjson解析Retrofit網路請求返回的資料)

public class FastJsonConverterFactory<T> extends Converter.Factory { private static final MediaType MEDIA_TYPE = MediaType.parse

Android小知識-剖析Retrofit中的網路請求流程以及相關引數

本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝! 在使用Retrofit時,需要建立Retrofit的例項,定義一個網路請求介面併為介面中的方法添加註解,接著通過動

Android小知識-剖析Retrofit網路請求的兩種方式

本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝! 在上一節《Android小知識-剖析Retrofit中ServiceMethod相關引數以及建立過程》介紹了動態代