Retrofit2.0起步篇

来源:http://www.cnblogs.com/qifengshi/archive/2016/11/14/6060520.html
-Advertisement-
Play Games

retrofit 英文名字是改裝的意思,也就是說他是對網路請求的一種改裝,他不負責進行網路請求,他是對請求方式的一種封裝。真正進行網路請求的是okhttp。 以下所有內容在Android Studio已經導入retrofit為基礎。導入方式如下: 利用Retrofit進行簡單的GET請求 retro ...


retrofit 英文名字是改裝的意思,也就是說他是對網路請求的一種改裝,他不負責進行網路請求,他是對請求方式的一種封裝。真正進行網路請求的是okhttp。
以下所有內容在Android Studio已經導入retrofit為基礎。導入方式如下:

  compile 'com.squareup.retrofit2:retrofit:2.1.0'
  compile 'com.squareup.retrofit2:converter-gson:2.1.0'
  compile 'com.squareup.retrofit2:converter-scalars:2.1.0'

利用Retrofit進行簡單的GET請求

retrofit在構建請求方式之前,需要構建一個介面方法,通過這個介面方法的返回值,來進行網路請求。
下麵,來通過一些簡單的例子瞭解GET請求。

實驗一:對一個簡單的html頁面進行GET請求

我們要獲取百度頁面的HTML。首先構建如下介面:

public interface HtmlService {
    @GET("/")
    Call<String> getHtml();
}

註意,GET註解中的參數,和方法中的參數至少要加一個,否則會報錯。由於,我們只需要請求www.baidu.com,所以get這裡不需要加參數,就是/
然後,我們通過如下步驟,來進行網路請求。
在我們需要進行網路請求的類中,通過以下的步驟,進行網路請求:

  1. 構建retrofit對象。
  2. 動態代理生成介面的對象。
  3. 通過介面的方法,得到要請求的API的調用。
  4. 通過同步/非同步的方式,得到response。
  5. 根據需要,處理response。

第一步

Retrofit retrofit = new Retrofit.Builder().          addConverterFactory(ScalarsConverterFactory.create()).
                baseUrl("https://www.baidu.com").
                build();

通過以上代碼,可以簡單的構建一個retrofit對象,addConverterFactory是對response進行解析,裡面添加的參數是表示對response用String解析,然後添加一個基礎的URL,後續的參數則是通過上面我們定製的介面來添加,最後構建一個完整的URL。
第二步

HtmlService htmlService = retrofit.create(HtmlService.class);

通過動態代理,生成一個介面的對象。

第三步

Call<String> call = htmlService.getHtml();

通過介面的方法得到調用的對象。

第四步與第五步
非同步方法得到response:

call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                showText.append(response.body());
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
            }
        });

得到的response,通過response.body()得到響應報文的body部分。
同步方法得到response:

new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    final String str = call.execute().body();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showText.append(str);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

實驗二:對一個返回JSON格式的API進行GET請求

通過GET請求GankIO的api得到Json:
首先,我們也是通過介面,構建一個介面方法:

@GET("content/{number}/{page}")
Call<HistoryBean> getHistoryData(@Path("number") String number,@Path("page") String page);

這裡,方法裡面傳入的參數會放到@GET的註解裡面。
然後,重新構建一個retrofit對象:

Retrofit retrofit = new Retrofit.Builder().
              addConverterFactory(GsonConverterFactory.create()).
                baseUrl("http://gank.io/api/history/").
                build();

這裡面添加的解析器是GsonConverterFactory,表示對response中body提供對象解析。然後的方法和上面類似:

 HtmlService htmlService = retrofit.create(HtmlService.class);
        call = htmlService.getHistoryData("2", "1");
call.enqueue(new Callback<HistoryBean>() {
            @Override
            public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) {
                HistoryBean hb = response.body();
                if(hb == null) return;
                showText.append(hb.isError() + "");
                for(HistoryBean.ResultsBean rb : hb.getResults()){
                    showText.append(rb.getTitle() + "/n");
                }
            }

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

            }
        });

上面的方法是非同步得到的,同步的方法和上面類似,就不多說了。

實驗三:添加一個請求參數構建GET請求

上面的GET方法是沒有查詢參數的,下麵對一個有查詢參數的api,進行GET請求,這裡我們利用豆瓣的搜索圖書的API
這個API接受4個搜索參數,具體如下:

參數 意義 備註
q 查詢關鍵字 q與tag必傳其一
tag 查詢的tag q與tag必傳其一
start 取結果的offset 預設為0
count 取結果的條數 預設為20

首先,我們也是構建一個請求介面的方法:

@GET("book/search")
Call<BookBean> queryBookInfo(@Query("q") String name);

在這裡面,我們用到了一個新的註解參數@Query 這個參數表示請求參數會以鍵值對的形式拼接在URL後面。
這樣的方式,有一種局限性,因為要在每個GET介面方法裡面寫入鍵值對信息,如果,有些鍵值對信息是每個GET方法都需要的,我們就會通過一個攔截器的形式,統一在請求的時候加上。步驟如下:

  1. 自定義一個攔截器實現Interceptor
  2. 創建retrofit的客戶端(上面的代碼都是預設的客戶端),加上這個攔截器。

第一步

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl httpUrl = request.url().newBuilder()
                .addQueryParameter("token", "tokenValue")
                .build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

第二步

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                connectTimeout(1000, TimeUnit.MILLISECONDS);
        
Retrofit retrofit = new Retrofit.Builder().
                client(httpClientBuilder.build()).
                addConverterFactory(GsonConverterFactory.create()).
                baseUrl("https://api.douban.com/v2/").
                build();
HtmlService htmlService = retrofit.create(HtmlService.class);
call = htmlService.queryBookInfo("第一行代碼");

後續的非同步請求基本一致,就不細說了。

實驗四:添加多種請求參數構建GET請求

實驗三的部分,講了對一個查詢參數和一個共有的查詢參數的GET請求構建方法,下麵多個查詢參數的GET請求,看看是否有簡單的方式,因為不想在一個方法里,傳入4個以上的參數。
請求的API還是上邊的豆瓣的搜索API,他正好有4個請求參數
下麵,看如下構建方式:

@GET("book/search")
Call<BookBean> queryBookInfo(@QueryMap Map<String,String> options);

然後,將請求參數通過鍵值對的形式保存到Map里:

 Map<String,String> options = new HashMap<>();
 options.put("q","第一行代碼");
 options.put("start","0");
 options.put("count","1");
 call = htmlService.queryBookInfo(options);

在上面的情況下,有多種鍵值對,每一種key對應的value都是唯一的,retrofit也支持相同的key,卻有多種value的形式。方式如下:

@GET("book/search")
Call<BookBean> queryBookInfo(@Query("key") List<String> value);

然後,將value的集合傳入方法中,後續的步驟不變,就不多數。

利用Retrofit進行簡單的POST請求

利用retorfit進行post請求與進行get請求沒有太多的區別。主要的區別就在構建介面方法上面,有一些不同,下麵通過一些實驗來看一下具體的區別。

實驗一:將少數參數放到請求體中進行POST請求

下麵的POST方法API是我自己寫的後臺來接受簡單的POST,就不放出來了。
首先,也是構建一個介面方法:

@FormUrlEncoded
@POST("login")
Call<String> doLogin(@Field("name")String name,@Field("password") String password);

第一個註解,表示自動將請求參數的類型調整為application/x-www-form-urlencoded ,如果方法參數的註解用了@Field 就一定要用@FormUrlEncoded。POST註解裡面依舊放的是API,方法參數通過@Field將請求參數放置在請求體中。
後續創建retrofit對象,創建call對象,發起請求,都是和GET方法一樣,就不多說了。

實驗二:將多個參數放到請求體中進行POST請求

這個只不過構建介面方法的時候,有所區別,其他步驟和多種參數進行GET請求一樣。

@FormUrlEncoded
@POST("login")
Call<String> doLogin(@FieldMap Map<String,String> fields);

將多個請求參數保存到Map中,傳入方法中,沒什麼好說的。

實驗三:利用POST進行文件上傳

同樣構建一個介面方法:

@Multipart
@POST("upload")
Call<ResponseBody> uploadFile(@Part("description") RequestBody description,
@Part MultipartBody.Part file);

這裡的POST修飾註解就換成了@Multipart ,在方法參數裡面,通過@Part註解來修飾參數。
我們說一下具體怎麼構建這些方法的參數。
首先,構建一個RequestBody對象的description,構建方式如下:

RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), "這是一個文件");

然後,構建一個MultipartBody.Part對象的file,不過在構建之前,先要創建一個RequestBody對象,通過這個對象才能創建一個MultipartBody.Part對象。代碼如下:

RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),file);
MultipartBody.Part body = MultipartBody.Part.createFormData("file",file.getName(),requestBody);

然後和其他方法一樣,利用這些對象,生成call,然後進行網路請求。

 call = service.uploadFile(description,body);

當然,retrofit支持多種上傳圖片的方式,其構建方式如下:

// 上傳多個文件
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadMultipleFiles(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file1,
            @Part MultipartBody.Part file2);

以上這些實驗就是利用Retrofit實現簡單POST 請求。

添加HEADER

我們在進行複雜的網路請求的時候,通常要對請求添加頭部,retrofit提供了多種添加方式,可以分為如下兩種:

  1. 靜態添加頭部
  2. 動態添加頭部

靜態添加頭部

靜態添加頭部,則每次請求的時候,頭部的信息都是固定的,不可以更改的。添加靜態頭部的方式也有多種,方法如下:

  1. 在介面中添加。
  2. 通過攔截器添加。

下麵,我們分別說一說每一種。
在介面中添加
還是以上文寫到的介面為例,添加Cache-Control,User-Agent請求頭部。

@Headers({
            "Cache-Control: max-age=640000",
            "User-Agent: app-name"
    })

通過攔截器添加
和上面統一處理GET參數的定製器一樣,同樣實現Interceptor,代碼如下:

public class RequestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request request = original.newBuilder()
                .header("User-Agent", "app-name")
                .header("Cache-Control", "max-age=640000")
                .method(original.method(), original.body())
                .build();
        return chain.proceed(request);
    }
}

然後,在創建okHttp的客戶端時,把攔截器加進去,創建retrofit對象時,指定該客戶端即可。

  OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                addInterceptor(new RequestInterceptor()).
                connectTimeout(1000, TimeUnit.MILLISECONDS);

動態添加頭部

動態添加的好處,就在於不同的請求會有不同的請求頭部,那麼可想而知,其添加的部分就是在介面方法裡面。

@GET("{number}/{page}")
Call<HistoryBean> getHistoryData(@Header("Content-Range") String contentRange ,@Path("number") String number, @Path("page") String page);

後續的使用都是一樣的,沒什麼好說的。

設置網路請求日誌

retrofit提供了對網路請求的過程進行列印的日誌的插件,需要單獨的導入,其方式如下:

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

通過上面的導入代碼,可以看出這個日誌插件是okHttp特有的,這也可以證明,retrofit只是封裝了請求的方式,真正請求的還是通過okHttp。那麼我們也可以猜出,其設置的方式必然也是通過攔截器,放進okHttp的客戶端裡面。具體的代碼如下:

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                addInterceptor(new RequestInterceptor()).
                addInterceptor(httpLoggingInterceptor).
                connectTimeout(1000, TimeUnit.MILLISECONDS);

註意上面的代碼,在設置請求級別上面設置為body,下麵說一下具體的級別以及其內涵:

  1. NONE : 沒有任何日誌信息。
  2. Basic : 列印請求類型,URL,請求體大小,返回值狀態以及返回值的大小。
  3. Headers : 列印返回請求和返回值的頭部信息,請求類型,URL以及返回值狀態碼
  4. Body : 列印請求和返回值的頭部和body信息。

總結

上面就是簡單的retrofit的使用,關於利用retrofit結合其他部分如Rx,okHttp等等,或者利用retrofit實現多種文件上傳,下載功能,保存cookie等等功能,可以期待後續的文章。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天學到了這個Loader,淺談一下自己的看法: 1.定義 Loader是一個載入器,可以用來它訪問數據,可以看做訪問數據的機器(好比挖掘機)。裝再器從android3.0開始引進,它使得在activity或fragment中非同步載入數據變得簡單。 具有如下特別: 1)它們對每個Activity和F ...
  • 轉載請標明出處:http://www.cnblogs.com/zhaoyanjun/p/6062880.html 本文出自 "【趙彥軍的博客】" 前言 以前我在 "【Android Handler、Loop 的簡單使用】" 介紹了子線程和子線程之間的通信。 很明顯的一點就是,我們要在子線程中調用Lo ...
  • 通常我們在處理耗時任務時候都會通過新建線程來處理,當任務處理完後通過Handler將結果發送回主線程。比如下麵示例: 那麼,我們能不能通過Handler從主線程發送消息給子線程呢?答案是肯定的,需要用到Looper.prepare()和Looper.loop()。如下麵的代碼: ...
  • 一、概要: 本文主要以Android的渲染機制、UI優化、多線程的處理、緩存處理、電量優化以及代碼規範等幾方面來簡述Android的性能優化 二、渲染機制的優化: 大多數用戶感知到的卡頓等性能問題的最主要根源都是因為渲染性能。 Android系統每隔16ms發出VSYNC信號,觸發對UI進行渲染, ...
  • AsyncTask,是android提供的輕量級的非同步類,可以直接繼承AsyncTask,在類中實現非同步操作,並提供介面反饋當前非同步執行的程度(可以通過介面實現UI進度更新),最後反饋執行的結果給UI主線程. 本文不分析AsyncTask的使用,它的使用教程網上一搜一大堆,本文主要分析它的內部邏輯和 ...
  • iOS開發中,發現UITextView沒有像UITextField中textFieldShouldReturn:這樣的方法,那麼要實現UITextView關閉鍵盤,就必須使用其他的方法,下麵是可以使用的幾種方法。 1.如果你程式是有導航條的,可以在導航條上面加多一個Done的按鈕,用來退出鍵盤,當然 ...
  • 綜上所述:這就是一個標準的的非同步操作,就像我們寄信一樣,我們只負責寫好信(Message)通過郵遞員(Handler)放入到郵箱(MessageQueue)中,由工作人員(Looper)去迴圈查詢,再由郵遞員處理(Handler)處理這些消息; //延遲兩秒跳轉 newHandler().postD ...
  • 1.自定義VideoView 1_自定義VideoView-增加設置視頻大小方法 2_得到屏幕高和寬方法 在播放器中 3_視頻預設和全屏 一播放起來,在準備好了中設置視頻播放預設 4_屏幕保持不鎖屏 5_點擊按鈕的時候實現切換播放模式 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...