Android 使用Retrofit請求API數據


概覽

Retrofit 是一個Square開發的類型安全的REST安卓客戶端請求庫。這個庫為網絡認證、API請求以及用OkHttp發送網絡請求提供了強大的框架 。理解OkHttp 的工作流程見  這個指南 。

注意本文是基於Retrofit2.0講解的 - 譯者注。

Retrofit 庫讓從web api下載JSON 或者xml數據變的非常簡單直接。一旦數據下載完成即將其解析成普通java類(POJO)。

設置

首先確保在AndroidManifest.xml中請求了網絡權限 :

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2.     <uses-permission android:name="android.permission.INTERNET" />
  3. </manifest>

在app/build.gradle文件中添加如下代碼:

  1. dependencies {
  2.     compile 'com.google.code.gson:gson:2.3'
  3.     compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
  4.     compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'  
  5.     compile 'com.squareup.okhttp:okhttp:2.4.0'
  6. }

過去,Retrofit 依賴於Gson 庫來解析JSON數據。 Retrofit 2 現在支持許多種解析方式來解析響應數據,包括 Moshi,一個由Square 創建的高效JSON解析庫。

但是,它也存在一些 局限,,因此如果你不確定該使用哪種,就暫時使用Gson converter 吧。

有如下的解析庫可以選擇:

 

Converter Library
Gson com.squareup.retrofit:converter-gson:2.0.0-beta2
Jackson com.squareup.retrofit:converter-jackson:2.0.0-beta1
Moshi com.squareup.retrofit:converter-moshi:2.0.0-beta1
Protobuf com.squareup.retrofit:converter-protobuf:2.0.0-beta1
Wire com.squareup.retrofit:converter-wire:2.0.0-beta1
Simple XML com.squareup.retrofit:converter-simplexml:2.0.0-beta1

要能把json解析成數據對象,需要響應的Java對象(准確的講是類),因此我們需要先自己構造Java對象。

 

從資源中創建Java對象

本文討論了兩種方法。第一種是手動創建,這要求你學會如何使用 Gson 庫。第二種是自動生成,使用jsonschema2pojo。我們建議你使用手動的方式,因為這樣你能更好的理解自動生成代碼是如何工作的。

手動方式創建Java對象

 這篇指南 講述了關於如何利用Gson庫創建自己的數據對象來供Retrofit使用。它演示了如何使用Gson 接收來自Rotten Tomatoes API的數據,但是對於其他RESTful web service方法是相同的。

自動生成Java對象

假設你已經有了JSON的響應結果,訪問jsonschema2pojo

blob.png

你可以選擇注解方式為Gson,但這並不是完全必須的,因為java沒有它們也能工作。目前,我們暫且選擇None作為注解方式。(Retrofit1.9默認使用的是Gson解析,如果要和Retrofit一起使用,注解方式請選擇Gson。不然生成的駝峰命名方式會導致解析失敗)

blob.png

接下來,把JSON 輸出粘貼到文字輸入框中:

blob.png

點擊Preview 按鈕。你可以看到前面部分和下圖類似:

blob.png

把生成的類粘貼到項目的諸如models一類的子包之下,把類名Example重命名為反映數據模型的名稱。以這里為例,我們命名為User。

注意:生成的代碼中存在@Generated注解。安卓默認並沒有javax.annotation library里面的許多東西。如果你希望保留@Generated注解,你需要添加如下的依賴。更多信息參見Stack Overflow上的討論。或者,你可以直接刪除這個注解,完全沒有問題。

  1. dependencies {
  2.   provided 'org.glassfish:javax.annotation:10.0-b28'
  3. }

創建Retrofit 實例

要向一個api發送我們的網絡請求 ,我們需要使用 Retrofit builder 類並指定service的base URL (通常情況下就是域名)。    

  1. public static final String BASE_URL = "http://api.myservice.com";
  2. Retrofit retrofit = new Retrofit.Builder()
  3.     .baseUrl(BASE_URL)
  4.     .addConverterFactory(GsonConverterFactory.create())
  5.     .build();

還需注意我們要指定一個factory 來對響應進行反序列化,使用的是 Gson library。就如這個視頻演講中所說的,converters 被添加的順序將是它們被Retrofit嘗試的順序。如果我們希望傳入一個自定義的Gson 解析實例,也是可以指定的:

  1. Gson gson = new GsonBuilder()
  2.         .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
  3.         .create();
  4.  
  5. Retrofit retrofit = new Retrofit.Builder()
  6.     .baseUrl(BASE_URL)
  7.     .addConverterFactory(GsonConverterFactory.create(gson))
  8.     .build();

添加多個converters - 譯者注。

blob.png

定義 Endpoints

在Retrofit 2中,endpoints是定義在一個interface里面的(其實1.9版本也是,只是用法略有不同),使用特殊的retrofit 注解來映射參數以及請求方法這些細節。另外,返回值始終是一個參數化了的Call<T>對象,比如Call<User>。如果你不需要任何類型安全的響應,你可以把返回值指定為Call<Response>。

比如,這個interface 用下面的方式定義了每個endpoint :

  1. public interface MyApiEndpointInterface {
  2.     // Request method and URL specified in the annotation
  3.     // Callback for the parsed response is the last parameter
  4.  
  5.     @GET("/users/{username}")
  6.     Call<User> getUser(@Path("username") String username);
  7.  
  8.     @GET("/group/{id}/users")
  9.     Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
  10.  
  11.     @POST("/users/new")
  12.     Call<User> createUser(@Body User user);
  13. }

注意到每個endpoint 都指定了一個關於HTTP(GET, POST, 等等。)  方法的注解以及用於分發網絡調用的方法。而且這些方法的參數也可以有特殊的注解。

注解 描述
@Path variable substitution for the API endpoint (i.e. username will be swapped for {username} in the URL endpoint).
@Query specifies the query key name with the value corresponding to the value of that annotated parameter.
@Body payload for the POST call

修改 base URL

一般地,base URL是在實例化 Retrofit instance的時候定義的。Retrofit 2 允許你在注解里面重寫base URL 。

  1.  @POST("https://api.github.com/api/v3")

就如 這篇文章(中文地址: Retrofit 2.0)所討論的,還有一些允許你使用相對路徑(不是完整的URL)修改 base URL的方法。

Multipart forms

如果你要提交多參數表單數據(multi-part form data),可以使用@Multipart與@Part注解:

  1. @Multipart
  2. @POST("/some/endpoint")
  3. Call<SomeResponse> someEndpoint(@Part("name1") String name1, @Part("name2") String name2)

Form URL encoding

如果我們希望提交 form-encoded name/value ,我們可以使用@FormUrlEncoded 與 @FieldMap注解:

  1. @FormUrlEncoded
  2. @POST("/some/endpoint")
  3. Call<SomeResponse> someEndpoint(@FieldMap Map<String, String> names);

Upgrading from Retrofit 1

如果你是想從 Retrofit 1升級過來,你應該記得在1.x版本中,如果你想定義一個異步的API請求而非同步請求,最后一個參數必須是Callback類型:

  1. public interface MyApiEndpointInterface {
  2.     // Request method and URL specified in the annotation
  3.     // Callback for the parsed response is the last parameter
  4.  
  5.     @GET("/users/{username}")
  6.     void getUser(@Path("username") String username, Callback<User> cb);
  7.  
  8.     @GET("/group/{id}/users")
  9.     void groupList(@Path("id") int groupId, @Query("sort") String sort, Callback<List<User>> cb);
  10.  
  11.     @POST("/users/new")
  12.     void createUser(@Body User user, Callback<User> cb);
  13. }

Retrofit 1 依賴於這個Callback類型作為最后一個參數,決定api請求是異步的。為了避免出現兩種不同的調用模式,這個接口在Retrofit 2被統一了。現在你可以直接定義返回值為一個參數化了的Call<T>,如前面小節所講。

Accessing the API

我們現在可以把這些東西放在一起:

  1. MyApiEndpointInterface apiService =
  2.     retrofit.create(MyApiEndpointInterface.class);

如果我們想異步請求這個API,我們如下調用這個service (注意取名為service 是Retrofit 的慣例,並不是語法的一部分):

  1. String username = "sarahjean";
  2. Call<User> call = apiService.getUser(username);
  3. call.enqueue(new Callback<User>() {
  4.     @Override
  5.     public void onResponse(Response<User> response) {
  6.         int statusCode = response.code();
  7.         User user = response.body();  
  8.     }
  9.  
  10.     @Override
  11.     public void onFailure(Throwable t) {
  12.         // Log error here since request failed
  13.     }
  14. });

如上所示,Retrofit 將在后台線程下載與解析API數據,然后通過onResponse或者 onFailure方法把結果發送回UI線程。

同步請求呢?更簡單,是這樣的:

  1. // Synchronous Call in Retrofit 2.0
  2. String username = "sarahjean"; 
  3. Call<User> call = apiService.getUser(username);
  4. User user = call.execute();

Retrofit與Authentication

使用Authentication Headers

可以使用一個Interceptor來為請求添加Headers。要發送請求到一個authenticated API,如下:

  1. // Define the interceptor, add authentication headers
  2. Interceptor interceptor = new Interceptor() {
  3.   @Override
  4.   public Response intercept(Chain chain) throws IOException {
  5.     Request newRequest = chain.request().newBuilder().addHeader("User-Agent", "Retrofit-Sample-App").build();
  6.     return chain.proceed(newRequest);
  7.   }
  8. };
  9.  
  10. // Add the interceptor to OkHttpClient 
  11. OkHttpClient client = new OkHttpClient();
  12. client.interceptors().add(interceptor);
  13.  
  14. // Set the custom client when building adapter
  15. Retrofit retrofit = new Retrofit.Builder()
  16.   .baseUrl("https://api.github.com")
  17.   .addConverterFactory(GsonConverterFactory.create())
  18.   .client(client)
  19.   .build();

注意在Retrofit 2中,interceptor 必須添加到一個自定義的OkHttpClient。而在Retrofit 1,它可以直接被builder 類設置。

使用 OAuth

為了用OAuth來認證,我們需要為每個網絡請求注冊一個特殊的header ,這個header 嵌入了在認證過程中為用戶獲取的access token。實際的認證過程需要使用第三方的library(比如signpost )完成,然后使用一個request interceptor把 access token添加到header中。Retrofit與authentication的相關鏈接列舉如下:

使用signpost認證的資料:

其它替代signpost的Android OAuth 庫:

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM