Android網絡編程(十一) 之 Retrofit2框架的使用

1 簡介

Retrofit是Square公司開發的Android裏對HTTP網絡請求的框架,官網是https://square.github.io/retrofit/。其底層是基於OkHttp實現的,也就是說Retrofit就對OkHttp的進一步封裝。Retrofit最大的特點就是簡潔易用,它使用了大量的運行時註解的方式來提供功能。

快速上手

假設有一服務器接口:https://api.xx.com/url.json?id=123,其請求後的返回值是

[
   {
      "app_name": "今日頭條",
      "package_name": "com.ss.android.article.news"
   },
   {
      "app_name": "騰訊新聞",
      "package_name": "com.tencent.news"
   },
   {
      "app_name": "鳳凰新聞",
      "package_name": "com.ifeng.news2"
   }
]

現在我們需要在代碼裏對其進行網絡請求,並將返回結果轉化成AppInfo對象。AppInfo類代碼如下所示:

AppInfo.java

public class AppInfo {
    private String app_name;
    private String package_name;

    @Override
    public String toString() {
        return "{app_name:" + app_name + ",package_name:" + package_name + "}";
    }
}

在build.gradle中添加支持庫依賴:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.6.2'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
}

在AndroidManifest.xml中聲明網絡請求權限:

<uses-permission android:name="android.permission.INTERNET"/>

於是我們使用Retrofit進行網絡請求的代碼可以這樣:

private void getRequest() {
    Retrofit retorfit = new Retrofit.Builder()
            .baseUrl("https://api.xx.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    AppInfoService appInfoService = retorfit.create(AppInfoService.class);
    Call<List<AppInfo>> call = appInfoService.getAppInfoList(123);
    call.enqueue(new Callback<List<AppInfo>>() {
        @Override
        public void onResponse(Call<List<AppInfo>> call, Response<List<AppInfo>> response) {
            List<AppInfo> appInfos = response.body();
            Log.e("zyx", appInfos.toString());
            Log.e("zyx", "當前線程:" + Thread.currentThread().getName());
        }

        @Override
        public void onFailure(Call<List<AppInfo>> call, Throwable t) {
            Log.e("zyx", t.toString());
            Log.e("zyx", "當前線程:" + Thread.currentThread().getName());
        }
    });
}
public interface AppInfoService {
    @GET("url.json")
    Call<List<AppInfo>> getAppInfoList(@Query("id") int id);
}

在你的代碼中執行getRequest方法,運行程序,便可見輸出如下結果,而且回調還會在主線程中進行:

2019-12-04 19:27:23.209 30842-30842/com.zyx.myapplication E/zyx: [{app_name:今日頭條,package_name:com.ss.android.article.news}, {app_name:騰訊新聞,package_name:com.tencent.news}, {app_name:鳳凰新聞,package_name:com.ifeng.news2}]
2019-12-04 19:27:23.212 30842-30842/com.zyx.myapplication E/zyx: 當前線程:main

3 介紹

3.1 庫的依賴和轉換器

要使用Rerofit庫,就必須在build.gradle中配置其依賴:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.6.2'
}

上述示例中除添加Rerofit庫外還添加了一個gson的庫。其實gson庫是可選的,默認情況下,Retrofit只能把HTTP響應結果反序列化成OkHttp的ResponseBody的類型並且只能接受它的RequsetBody的類型是@Body(後面介紹)。然而通過addConverterFactory方法可添加其它轉換器來支持其他的類型。可以通過添加如下依賴包來支持其序列化操作。

  1. Gson: com.squareup.retrofit2:converter-gson
  2. Jackson: com.squareup.retrofit2:converter-jackson
  3. Moshi: com.squareup.retrofit2:converter-moshi
  4. Protobuf: com.squareup.retrofit2:converter-protobuf
  5. Wire: com.squareup.retrofit2:converter-wire
  6. Simple XML: com.squareup.retrofit2:converter-simplexml

當然你也可以通過自定義的方式創建自己的轉換器,只要創建一個繼承於Converter.Factory的類並實現responseBodyConverter 和 requestBodyConverter方法,然後使用addConverterFactory添加適配器的時候傳入其一個實例就可以了。

3.2 請求方法註解

從上述示例中AppInfoService你會發現在getAppInfoList方法中就定義了一個@GET的註解,其實Rerofit裏頭很多是藉助註解來完成。HTTP請求方法註解有8種,它們是GETPOSTPUTDELETEHEADPATCHOPTIONSHTTP。其中前面7種分別對應HTTP的請求方法;而最後一種HTTP 是通用註解,可以通過參數來替換以上 7 種。使用如:

@HTTP(method = "GET", path = " url.json", hasBody = false)
Call<List<AppInfo>> getAppInfoList();

method             表示請求的方法,注意它是區分大小寫

path                  表示網絡請求地址路徑

hasBody           表示是否有請求體

3.3 請求頭註解

請求頭註解有兩種:Headers 和 Header。它們區別在於,前者一般用於固件的請求頭,可添加多個;而後者一般用於不固定請求頭,作爲方法的參數輸入,使用如:

@Headers({"Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App"})
@GET("url.json")
Call<List<AppInfo>> getAppInfoList(@Header("Authorization") String authorization);

3.3 參數類註解

參數類註解有:BodyPathFieldFieldMapPartPartMapQueryQueryMapUrl 等。

3.3.1 Body

用於Post請求發送HTTP請求體,比如已添加過GsonConverterFactory,則可將類對象傳入,使用如:

@POST("users/new")
Call<User> createUser(@Body User user);

3.3.2 Path

用於Url中的佔位符,使用如:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

3.3.3 Field 和 FieldMap

用於Post請求時以表單的形式傳遞參數,需要結合@FromUrlEncoded使用,使用如:

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@FieldMap Map<String, String> map);

3.3.4 Part 和 PartMap

用於Post請求時以表單的形式傳遞參數,與@Field區別於@Part可攜帶更加豐富的參數類型,比如用於文件上傳時可攜帶數據流,需要結合@Multipart使用,使用如:

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
@Multipart
@PUT("user/photo")
Call<User> updateUser(@PartMap Map<String, RequestBody> map);

3.3.5 Query 和 QueryMap

用於Get請求時傳遞參數,使用如:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

3.3.6 Url

用於指定請求路徑,使用如:

@GET
Call<List<AppInfo>> getAppInfoList(@Url String url, @Query("id") int id);

3.4 標記類註解

標記類註解有 3 種:FormUrlEncodedMultipartStreaming

3.4.1 FormUrlEncoded

用於Post請求時,請求實體是一個From表單的時,每個鍵值對需要使用@Field註解,使上如上面介紹Field 和 FieldMap。

3.4.2 Multipart

用於Post請求時,請求實體是豐富的參數類型,比如用於文件上傳時可攜帶數據流,每個鍵值對需要使用@Part註解,使上如上面介紹Part和PartMap。

3.4.3 Streaming

一般在下載比較大的文件時,需要添加@Streaming註解,表示響應字節流的形式返回,這樣就可避免大文件全部加載到內存中。

3.5 同步和異步

Call對象可以同步地或異步地進行網絡請求,而且每一個對象只能使用一次,若想執行多次可以調用clone()來創建一個新對象。還要注意的是,在Android中,回調會在主線程中執行,而在JVM中,回調會在與執行HTTP請求的相同線程。

同步執行示例代碼:

try {
    Response<List<AppInfo>> response = call.execute();
    List<AppInfo> appInfos = response.body();
    Log.e("zyx", appInfos.toString());
    
} catch (IOException e) {
    e.printStackTrace();
}

異步執行示例代碼:

call.enqueue(new Callback<List<AppInfo>>() {
    @Override
    public void onResponse(Call<List<AppInfo>> call, Response<List<AppInfo>> response) {
        List<AppInfo> appInfos = response.body();
        Log.e("zyx", appInfos.toString());
    }

    @Override
    public void onFailure(Call<List<AppInfo>> call, Throwable t) {
        Log.e("zyx", t.toString());
    }
});

看到上述同步和異步代碼後,你是不是有似曾相識的感謝。我們之前學習OkHttp中同步和異步請求也是差不多的代碼,因爲Rerofit框架底層本來就是使用了OkHttp的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章