Retrofit使用詳解-註解介紹

關於Retrofit的講解,我將寫下面系列篇文章進行總結:html

  • Get和Post請求的基本使用
  • 上傳圖片
  • 下載文件
  • 添加攔截器
  • ...(和RxJava聯合使用、RxJava+Retrofit+OkHttp簡單封裝、統一錯誤處理)

講解以前我必須先安利個網站模客,在學習Retrofit以前,各類網絡請求若是想學習的話就必須有接口才能訪問,Get請求還好說,但遇到Post請求,本身發送的是啥也不清楚,苦於本身不會後端寫接口,因此以前對Retrofit的學習要麼是各類找現成的API,要麼就只是照貓畫虎的敲了下並無實踐,有了這個網站你就能夠本身寫接口本身訪問來測測看Retrofit的運用到底對不對。java

具體該網站的使用見模客的使用這篇文章,下面咱們來學習Retrofit的使用吧android

1. Retrofit的基本使用

1.1 添加依賴

//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
//Gson converter
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
複製代碼

第二個依賴主要是對Json數據進行解析的。git

1.2 實現步驟

  • 建立網絡請求的接口
  • 建立Retrofit實例
  • 建立網絡請求接口的實例
  • 發送網絡請求

官網同樣,能夠看下官網介紹的代碼,就是上面所寫的步驟github

  • public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    複製代碼
  • Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    複製代碼
  • GitHubService service = retrofit.create(GitHubService.class);
    複製代碼
  • Call<List<Repo>> repos = service.listRepos("octocat");
    複製代碼

1.3 具體實現

下面我將介紹個具體的例子,讓沒用過Retrofit的先熟悉下Retrofit如何使用json

1.3.1 建立網絡請求的接口

public interface GetApi {

    /** * 獲取用戶信息 * @return * @Query 註解 */
    @GET("getUserInfo")
    Call<UserInfo> getUserInfo(@Query("id") String userId);

}
複製代碼

這個@Query註解是什麼能夠先不用管,下面會詳細講解。後端

UserInfo是咱們獲得返回數據的數據Bean類api

1.3.2 建立Retrofit實例

private Retrofit retrofit;
retrofit = new Retrofit.Builder()
    .baseUrl("http://mock-api.com/2vKVbXK8.mock/")
    .addConverterFactory(GsonConverterFactory.create()) //返回的Json數據進行解析
    .build();
複製代碼

baseUrl:安全

這裏的baseUrl是本身訪問的Url的基類地址,加上剛纔@GET("getUserInfo")中的getUserInfo纔是咱們真正要訪問的地址,由於使用了@Query("id"),因此最終的訪問地址爲bash

http://mock-api.com/2vKVbXK8.mock/getUserInfo?id=userid,此處的userid爲本身傳入的參數。

注意: baseUrl必需要以/結尾!!!

addConverterFactory:

加這個addConverterFactory(GsonConverterFactory.create())固定的,則會將返回的Json數據直接解析爲咱們的數據Bean類

1.3.3 建立網絡請求接口的實例

private GetApi getApi;
getApi = retrofit.create(GetApi.class);
複製代碼

1.3.4 發送網絡請求

getApi.getUserInfo(userid).enqueue(new Callback<UserInfo>() {
    @Override
    public void onResponse(Call<UserInfo> call, Response<UserInfo> response) {
        if (response != null && response.body() != null) {
            //此處爲獲取到的信息
            UserInfo userInfo = response.body();
        }
    }

    @Override
    public void onFailure(Call<UserInfo> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);
    }
});
複製代碼

使用時別忘了申請網絡權限哦,使用時可能會遇到如下問題:

CLEARTEXT communication to mock-api.com not permitted by network security policy

這是由於Android P不容許明文訪問,而前面的mock地址是http開頭的,解決辦法是在AndroidManifest中的application內加入下面這段代碼便可:

android:usesCleartextTraffic="true"
複製代碼

以上就是Retrofit最基本的一次網絡請求,接下來咱們詳細看下Retrofit網絡請求接口中主要有哪些註解。

2. Get請求

baseUrl爲:http://mock-api.com/2vKVbXK8.mock/

2.1 @Query

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/getUserInfo?id=1234 //1234爲傳來的參數
複製代碼

實例

@GET("api/getUserInfo")
Call<UserInfo> getUserInfo(@Query("id") String userId);
複製代碼
public class UserInfo { 
    private String userId;
    private String userName;
    private String describe;
}
複製代碼

當咱們要訪問的地址爲:baseUrl+getUserInfo?id=1234,以?形式拼接一個參數這種格式時,就使用@Query註解,該註解就是在getUserInfo後面添加?,而且以id=傳來的參數userId的形式拼接url

2.2 @QueryMap

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/getArticalInfo?id=405&page=1
複製代碼

實例

@GET("api/getArticalInfo")
Call<ArticalInfo> getArticalInfo(@QueryMap Map<String, String> params);
複製代碼
public class ArticalInfo {   
    private String articalName;
    private String url;
}
複製代碼

當要訪問的地址是經過?形式拼接多個參數時就使用@QueryMap註解

具體使用:

Map<String, String> params = new HashMap<>();
params.put("id", "405");
params.put("page", "1");

getApi.getArticalInfo(params).enqueue(new Callback<ArticalInfo>() {
    @Override
    public void onResponse(Call<ArticalInfo> call, Response<ArticalInfo> response) {
        if (response != null && response.body() != null) {
            Log.i(TAG, "onRespons:" + response.body().toString());
        }
    }
    @Override
    public void onFailure(Call<ArticalInfo> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);
    }
});
複製代碼

2.3 @Path

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/getDynamicInfo/1/data
http://mock-api.com/2vKVbXK8.mock/api/getDynamicInfo/2/data
複製代碼

實例

@GET("api/getDynamicInfo/{param}/data")
Call<ResponseBody> getDynamicInfo(@Path("param")int param);
複製代碼

當要訪問的地址由某個參數動態拼接而成時,使用@Path註解,上面實例中param這裏具體填入的內容是後面調用該方法時傳入的參數

getApi.getDynamicInfo(param).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);           
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);
    }
});
複製代碼

你們仔細看下,你會發現Call<ResponseBody>這裏和上面的不一樣,這裏填入的是ResponseBody,當返回的具體數據不是咱們知道的Bean類時能夠用這個,這樣,咱們能夠經過上述字符串的形式獲取到返回的內容。

2.4 @Url

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/getDynamicUrlData
複製代碼

實例

@GET
Call<ResponseBody> getDynamicUrl(@Url String url);
複製代碼

當要訪問的地址不僅是動態的變幾個參數,而是整個地址都要變化,甚至是基類地址也要變化時,這種動態地址就要用到@Url註解

具體使用

String url = "http://mock-api.com/2vKVbXK8.mock/api/getDynamicUrlData"
    
getApi.getDynamicUrl(url).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);
    }
});    
複製代碼

因此說這個註解很方便,上面全部註解所訪問的連接都可經過此註解傳入完整的Url進行訪問。

注意

雖說最終訪問的地址與原先的baseUrl無關,可是baseUrl仍是要以http://https://開頭,而且後面至少要跟一個字母或者其餘東西,否則就會報錯。

http://				
複製代碼

寫成這個會報Invalid URL host: ""錯誤

http://a
複製代碼

我實際測試時,這個a這裏寫什麼均可以,沒有以/結尾也能夠

2.5 @Headers("")

靜態添加頭部信息:包含添加單個頭部、添加多個頭部

經過@Headers("")註解,內部以key:value的方式填寫內容

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/staticHeaderInfo
複製代碼

實例

靜態添加單個頭部

@Headers("version:1.1")
@GET("api/staticHeaderInfo")
Call<GetBean> getStaticHeadersInfo();
複製代碼

靜態添加多個頭部

@Headers({"version:1.1",
            "type:android"})
@GET("api/staticHeadersInfo")
Call<GetBean> getStaticMoreHeadersInfo();
複製代碼

模客後臺

經過觀察模客模擬器的匹配日誌,能夠看到咱們訪問時確實加上了頭部信息

2.6 @Header

動態添加單個頭部信息

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/dynamicHeadersInfo
複製代碼

實例

@GET("api/dynamicHeadersInfo")
Call<ResponseBody> getDynamicHeaderInfo(@Header("version") String version);
複製代碼
getApi.getDynamicHeaderInfo("1.1.1").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {        
    }
});
複製代碼

模客後臺

能夠看到咱們訪問時確實在頭部加入了version=1.1.1的信息。

2.7 @HeaderMap

動態添加多個頭部信息

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/dynamicHeadersInfo
複製代碼

實例

@GET("api/dynamicHeadersInfo")
Call<ResponseBody> getDynamicHeadersInfo(@HeaderMap Map<String, String> headers);
複製代碼
Map<String, String> headers = new HashMap<>();
headers.put("version", "2.2.2");
headers.put("type", "Android");

getApi.getDynamicHeadersInfo(headers).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
    }
});
}
複製代碼

模客後臺

能夠看到咱們在訪問的時候兩個頭部信息已經加載header中

3. Post請求

對比着Get請求中的註解,Post請求中的註解就很好記了。

@Field 對應 @Query

@FieldMap 對應 @QueryMap

@Body 對應 @Url

注意

在Post請求中,儘可能不要使用@Query和@QueryMap,由於它傳入的參數是直接拼接在url上的,不安全,而@Field和@FieldMap是寫入到Body中的。

3.1 @FormUrlEncoded

@FormUrlEncoded用於修飾@Field註解和@FieldMap註解,將會自動將請求參數的類型調整爲

application/x-www-form-urlencoded

3.2 @Field

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/fieldParam
複製代碼

實例

@FormUrlEncoded
@POST("api/fieldParam")
Call<ResponseBody> postFieldFun(@Field("key") String key);
複製代碼

記得加上@FormUrlEncoded,不然會報如下錯誤:

@Field parameters can only be used with form encoding
複製代碼

使用

private PostApi postApi;
postApi = retrofit.create(PostApi.class);

postApi.postFieldFun("myfittinglife").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);           
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);
    }
});
複製代碼

模客後臺

能夠看到咱們經過@Field註解添加的參數是寫在body中而不是直接拼接在Url後面

這裏是根據咱們設立的規則來進行匹配的,固然咱們也能夠選擇文本或其餘的方式進行匹配。

3.3 @FieldMap

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/fieldMapParam
複製代碼

實例

@FormUrlEncoded
@POST("api/fieldMapParam")
Call<ResponseBody> postFildMapFun(@FieldMap Map<String, String> params);
複製代碼

@FieldMap時候於多個相同類型參數的傳遞

使用

Map<String, String> params = new HashMap<>();
params.put("key", "myfittinglife");
params.put("password", "123456");

postApi.postFildMapFun(params).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);       
    }
});
複製代碼

模客後臺

能夠看到咱們傳入body內的兩個參數

3.4 @Body

3.3 能夠看到@FieldMap註解適合多個相同類型參數的傳遞,若是多個不一樣類型傳遞的話,總不能寫多個@Field

Call<ResponseBody> postFieldFun(@Field("key") String key,@Field("num")int num);

若是要更多種類型的話那就更繁瑣了,因此這裏咱們能夠用@Body註解,直接傳入一個對象過去,對象內可包含多種類型數據。

訪問地址

http://mock-api.com/2vKVbXK8.mock/api/bodyParam
複製代碼

實例

@POST("api/bodyParam")
Call<ResponseBody> postBodyFun(@Body PostBodyBean postBodyBean);
複製代碼
public class PostBodyBean {
    private String key;
    private int num;
    private boolean isTrue;
}
複製代碼

使用

PostBodyBean postBodyBean = new PostBodyBean("myfittinglife",1,true);
postApi.postBodyFun(postBodyBean).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: " + t);        
    }
});
複製代碼

模客後臺

能夠看到咱們傳的Body

注意

使用@Body註解必定在建立Retrofit的時候加上.addConverterFactory(GsonConverterFactory.create()),目的是將對象轉化爲json字符串進行傳遞,不然會報如下錯誤

Unable to create @Body converter for class PostBodyBean 複製代碼

3.5 @Part/@PartMap

這兩個註解和文件上傳相關,在後面的文章中會進行詳細講解。

4. 注意

  • 訪問地址http開頭,記得在AndroidManifest內的application中加入android:usesCleartextTraffic="true"

  • GET請求不能使用@Body註解

  • baseUrl網址末尾必定加/斜槓

  • @Body註解必定要加.addConverterFactory(GsonConverterFactory.create())

  • 當@GET或@POST註解的url爲全路徑時(可能和baseUrl不是一個域),會直接使用註解的url的 域。

  • 使用@Path註解時,path對應的路徑不能包含/,不然會將其轉化爲%2F,報以下錯誤。在遇到想動態的拼接多節url時,仍是使用@Url吧。

    Attempt to invoke virtual method 'byte[] okhttp3.ResponseBody.bytes()' on a null object reference
    複製代碼

5. 總結

以上就是關於Retrofit的一些註解的基本使用介紹,具體代碼見Github.

爲了簡便觀察,文章中只是使用了一個註解來創建接口,其實在實際使用時,能夠多個註解連用,例以下面所示:

@GET("api/{param}/getUserInfo")
Call<UserInfo> getUserInfo(@Path("params") String param, @Query("id") String userId);
複製代碼

具體怎麼結合仍是要根據實際項目提供的url來使用。以上就是所有內容,能力有限,不對的地方還望指出,有幫助的話還望點個start,下篇文章見。

6. 參考文章

Retrofit官方Github地址

Retrofit官網

說說Retrofit中的註解

相關文章
相關標籤/搜索