Android體系課學習 之 網路請求庫Retrofit使用方式(附Demo)

語言: CN / TW / HK

highlight: a11y-light theme: smartblue


前言

  • 網路請求在我們開發中起的很大比重,有一個好的網路框架可以節省我們的開發工作量,也可以避免一些在開發中不該出現的bug

  • Retrofit是一個輕量級框架,基於OkHttp的一個Restful框架

微信圖片_20220527220425.png 今天我們來看下Retrofit的具體使用方式

Android體系課學習 之 開源框架系列

[Android體系課學習 之 網路請求庫OkHttp使用方式(附Demo)]()

[Android體系課學習 之 網路請求庫OkHttp看這一篇就夠了]()

[Android體系課學習 之 網路請求庫Retrofit使用方式(附Demo)](https://juejin.cn/post/7103518717471883277)

[Android體系課學習 之 網路請求庫Retrofit原始碼分析](https://juejin.cn/post/7104121838749843492)

[Android體系課學習 之 RxJava看這篇就夠了]()

[Android體系課學習 之 RxJava操作符詳解]()

[Android體系課學習 之 RxJava原始碼分析]()

1.目錄

Retrofit 2.0目錄介紹.png

2.簡介

  • 功能

    • 使用介面方法註解的方式配置網路請求引數
  • 優點

    • 功能強大:支援同步和非同步,支援自定義資料解析型別,常用如Json
    • 支援多平臺,如Android,Java8等
    • 使用簡單:通過註釋的方式動態配置交易請求引數
    • 使用多種設計模式,對模組之間解耦,拓展性好
    • 目前最新版本支援協程的方式進行網路請求,不需要再指定使用同步還是非同步方式
  • 使用場景

    支援所有的網路請求場景,特別是請求次數比較頻繁的場景,因為內部是基於OkHttp,而OkHttp內部使用了各種攔截器,且對請求有做快取IO複用操作,防止短時間重複連線操作,浪費資源。

需要注意:Retrofit請求的本質是通過OkHttp傳送網路請求,而Retrofit只是負責網路前期介面的封裝

retrofit網路流程.png

3.使用教程

Retrofit使用步驟如下: 

  • 步驟1:新增Retrofit庫依賴
  • 步驟2:根據伺服器響應格式建立響應類
  • 步驟3:建立網路請求介面並添加註解
  • 步驟4:建立Retrofit例項
  • 步驟5:建立網路請求例項
  • 步驟6:呼叫網路請求方法
  • 步驟7:處理網路請求返回

步驟1:新增Retrofit庫依賴

在模組的build.gradle中新增

implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

在manfest中新增網路許可權

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

步驟2: 根據伺服器響應格式建立響應類、

假如伺服器給了以下請求響應格式:對應了Translation這個響應類,

一個使用中括號括起來的資料格式代表一個新的類:如格式中的message,baesInfo等由於是另起一箇中括號,所以需要建立一個內部類

{ "status" :1, “message”:{ “baesInfo”:{ “from”:“eng” “to” : “CN” “translate_result”:“hello” } “word_name”:“你好” } }

/** * 建立解析類 */ public class Translation { private int status; private message message; private static class message { private baesInfo baesInfo; private String word_name; } private static class baesInfo { private String from; private String to; private String translate_result; } }

步驟3: 建立網路請求介面並添加註解

Retrofit將網路請求抽象成一個介面,並使用註解的方式配置網路請求引數和方法

1.用動態代理的方式將請求解析為一個Http請求,並執行這個請求

2.介面中每個方法的引數都需要使用註釋的方式完成。

``` /**

  • 建立用於描述網路請求的介面
    */
    public interface RequestInterface{
    @GET("/dictionary/word/query/v2?client=1&timestamp=1637143127&isChangeTo=0&sign=63243e0fb77fa81e&uuid=d6ceb7789ff04ff69355cea0a3325e40&sv=android10&v=11.1.7&uid=&translateType=-1&key=1000001&identity=12&word=%25E4%25BD%25A0%25E5%25A5%25BD%25E5%25B0%258F%25E5%25A7%2590&signature=7cdc8cee1566bde7c34a817fbab31a20")
    Call getCall();
    // 註解裡傳入 網路請求 的部分URL地址
    // Retrofit把網路請求的URL分成了兩部分:一部分放在Retrofit物件裡,另一部分放在網路請求接口裡
    // 如果接口裡的url是一個完整的網址,那麼放在Retrofit物件裡的URL可以忽略
    // getCall()是接受網路請求資料的方法
    } ```
註解詳細說明:
第一類:網路請求方法註釋

| 型別 | 名稱 | 解釋 | | ---- | --------------------------------------------- | -------------------------------------------------------------- | | 請求方法 | @GET,@POST ,@PUT,@DELETE,@PATH,@HEAD,@OPTIONS | 所有請求都對應一個網路請求方法,接收一個URL地址,如果設定了baseUrl,則完整地址= baseUrl+這裡設定的url | | | @HTTP | 替換以上七個註解 |

這裡對URL地址組成做個詳細說明:

  • 網路請求完整url = 建立Retrofit的時候設定的baseUrl+網路請求介面註解設定的路徑path

如果path是一個完整路徑,則無需再配置baseUrl,否則會報錯

來講下HTTP註釋

  • HTTP註釋主要是用來取代之前請求方式GET,POST等的操作,擴充套件性更強

  • 如下面這個呼叫方式:

    下面的例子使用HTTP取代POST方式,並在path中傳遞一個引數,來動態配置url

``` public interface RequestInterface {
/*
* method:請求方式
* path:請求路徑 {user}:表示需要從引數中傳入
* hasBody:請求體是否存在
* @param user
* @return
/
@HTTP(method = "POST",path = "select/{user}",hasBody = false)
Call getCall(@Path("user") int user);

} ```

第二類:網路請求標記註釋

標記類註釋主要包括三個:

  • @FormUrlEncoded:表示請求體是一個form表單

    每個鍵值對以Field的形式傳入

    使用方式如下:

    /** * FormUrlEncoded:表示該請求體是一個表單格式(Content-Type:application/x-www-form-urlencoded) * @Field ("userName") String name:表示以userName為key,以name為值的表單資料 * */ @HTTP(method = "POST",path = "select/{user}",hasBody = false) @FormUrlEncoded Call<Translation> showFULAnnotation(@Field ("userName") String name,@Field ("pwd") String pwd,@Path("user") int user); 具體呼叫: RequestInterface rq = retrofit.create(RequestInterface.class); Call<Translation> call1 = rq.showFULAnnotation("name","123456",123);

  • @Multipart:表示請求實體是一個form,適用於有檔案上傳的場景

    每個鍵值對以Part形式傳入

    使用方式如下:

    ``` /* * Multipart:表示該請求體是一個表單格式(Content-Type:application/x-www-form-urlencoded),且支援檔案上傳 * @Part ("userName") String name:表示以userName為key,以name為值的表單資料 * @Par MultipartBody.Part file ,表示fileText是一個Part,內部包含了一個key和body * Part後面可以是:RequestBody或者MultipartBody.Part * / @HTTP(method = "POST",path = "select/{user}",hasBody = false) @Multipart Call showMultipart(@Part("userName") RequestBody name, @Part ("pwd") RequestBody pwd, @Part MultipartBody.Part fileText , @Path("user") int user);

    //呼叫處: RequestInterface rq1 = retrofit.create(RequestInterface.class); RequestBody bodyName = RequestBody.create(MediaType.get("text/plain"),"yuhb"); RequestBody bodyPwd = RequestBody.create(MediaType.get("text/plain"),"123"); //這裡獲取檔案系統中的資料,並傳給MultipartBody.Part File file = new File("/aa/bb/file.png"); RequestBody bodyFile = RequestBody.create(MediaType.get("image/png"),file); MultipartBody.Part part = MultipartBody.Part.createFormData("MyFile","testFile.text",bodyFile); rq1.showMultipart(bodyName,bodyPwd,part,123); ```

  • @Streaming:適用於一些返回資料量比較大的場景,如下載大資料等,並且以流的形式返回

第三類:網路請求引數註解

a)@Header和@Headers

定義:設定請求頭

兩者區別:

  • Headers新增的是固定的頭而Header是新增不固定的頭

  • Headers作用在方法上,而Header作用在引數上

    使用方式如下:

    ``` / 這裡使用Header註解引數動態傳入Header資料,可以設定多個Header / @GET("/get") Call showHeader(@Header("Content") String content);

    /**
     *這裡使用Headers註解方法設定頭資料,只能設定一次
     */
    @Headers("Content:content")
    @GET("/get")
    Call<Translation> showHeaders();
    

    ```

b)@Body

定義:傳入一個物件作為Body傳入引數,作為POST的請求body

作用類似於FieldMap

使用方式如下:

``` / 這裡使用Body註解修飾了一個Bean物件, / @POST("/post") Call showBody(@Body Bean bean);

//這裡呼叫:
rq1.showBody(new Bean("yuhb","28","love you"));

```

步驟4:建立Retrofit例項

Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://dict.iciba.com/") // 設定 網路請求 Url .addConverterFactory(GsonConverterFactory.create()) //設定使用Gson解析(記得加入依賴            ) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支援RxJava平臺 .build();

a 關於資料解析器
  • Retrofit支援多種資料解析方式

  • 需要在專案build.gradle中新增對應依賴

    常用的是Gson解析器:

    implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

b 關於網路介面卡

Retrofit支援多種介面卡

使用時如使用的是 Android 預設的 CallAdapter,則不需要新增網路請求介面卡的依賴,否則則需要按照需求進行新增\ Retrofit 提供的 CallAdapter

步驟5:建立網路請求例項

GetRequest_Interface request = retrofit.create(RequestInterface.class); Call<Translation> call = request.getCall();

步驟6:呼叫網路請求方法

這裡使用了非同步的方式,還可以使用同步的方式,同步會阻塞執行緒,所以切記在主執行緒上呼叫同步的方式

``` //非同步呼叫 call.enqueue(new Callback() { //請求成功時回撥 @Override public void onResponse(Call call, Response response) { // 步驟7:處理返回的資料結果 response.body().show(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(RetrofitTestActivity.this,""+response.body().getResult(),Toast.LENGTH_SHORT).show(); } }); }

        //請求失敗時回撥
        @Override
        public void onFailure(Call<Translation> call, Throwable throwable) {
            System.out.println("連線失敗");
        }
    });

//同步呼叫 call.execute(); ```

4.專案實戰

  • 首先我們使用ApiPost 的mock server功能mock出一個登入api介面

mockserver.png

介面型別:POST

mock伺服器地址:

https://console-mock.apipost.cn/app/mock/project/a050bb0d-28d9-48fd-c7db-b2953f7f1caf/api/demo/login

響應資料格式:

{ "code": "0000", "data": { "verifySuccess": true, "userInfo": { "username": "admin", "email": "[email protected]", "address": "@address" } }, "desc": "成功" }

  • 步驟1:根據響應資料格式,我們建立響應資料轉換類:

每個中括號代表一個類

``` / 響應資料類 * / public class Result{ String code; Data data; class Data{ boolean verifySuccess; UserInfo userInfo;

    @Override
    public String toString() {
        return "Data{" +
                "verifySuccess=" + verifySuccess +
                ", userInfo=" + userInfo +
                '}';
    }

    class UserInfo{
        String username;
        String email;
        String address;

        @Override
        public String toString() {
            return "UserInfo{" +
                    "username='" + username + ''' +
                    ", email='" + email + ''' +
                    ", address='" + address + ''' +
                    '}';
        }
    }

}

@Override
public String toString() {
    return "Result{" +
            "code='" + code + ''' +
            ", data=" + data +
            '}';
}

} ```

請求api:

請求介面.png

步驟2:根據請求api建立請求介面類

``` public interface RequestInterface { / * FormUrlEncoded:只是請求Body為一個Form表單 / @FormUrlEncoded @POST("api/demo/login") Call login(@FieldMap Map map);

/**
 * FormUrlEncoded:只是請求Body為一個Form表單
 **/
@FormUrlEncoded
@POST("api/demo/login")
Call<Result> login(@Field("username") String username,
                   @Field("password") String password,
                   @Field("mobile") String mobile,
                   @Field("ver_code") String ver_code);

} ```

請求方法:POST 請求URL:這裡使用baseUrl+url路徑(api/demo/login) 請求介面:使用了@Field和@FieldMap兩種模式,在引數比較多的情況下,應該使用@FieldMap的註解表示引數輸入

呼叫了FormUrlEncoded表示該請求實體是一個表單。

步驟3:建立Retrofit例項 1.設定baseUrl 2.設定GsonConverterFactory資料解析器;

記得新增依賴:

implementation com.squareup.retrofit2:converter-gson:2.0.9

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://console-mock.apipost.cn/app/mock/project/a050bb0d-28d9-48fd-c7db-b2953f7f1caf/") .addConverterFactory(GsonConverterFactory.create()) .build();

步驟4:獲取請求代理類

RequestInterface request = retrofit.create(RequestInterface.class); Call<Result> call = request.login("admin","123456","18289454846","123456");

步驟5:呼叫enqueue非同步傳送請求

``` call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { System.out.println(response.body()); }

        @Override
        public void onFailure(Call<Result> call, Throwable t) {
            System.out.println(t.getMessage());
        }
    });

```

步驟6:對響應進行處理 列印成功或者失敗資訊

執行結果:

Result{code='0000', data=Data{verifySuccess=true, userInfo=UserInfo{username='admin', email='[email protected]', address='@address'}}}`

Demo地址https://github.com/ByteYuhb/DemoRetrofit

5.總結