關於Retrofit的講解,我將寫下面系列篇文章進行總結:html
- Get和Post請求的基本使用
- 上傳圖片
- 下載文件
- 添加攔截器
- ...(和RxJava聯合使用、RxJava+Retrofit+OkHttp簡單封裝、統一錯誤處理)
講解以前我必須先安利個網站模客,在學習Retrofit以前,各類網絡請求若是想學習的話就必須有接口才能訪問,Get請求還好說,但遇到Post請求,本身發送的是啥也不清楚,苦於本身不會後端寫接口,因此以前對Retrofit的學習要麼是各類找現成的API,要麼就只是照貓畫虎的敲了下並無實踐,有了這個網站你就能夠本身寫接口本身訪問來測測看Retrofit的運用到底對不對。java
具體該網站的使用見模客的使用這篇文章,下面咱們來學習Retrofit的使用吧android
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
//Gson converter
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
複製代碼
第二個依賴主要是對Json數據進行解析的。git
和官網同樣,能夠看下官網介紹的代碼,就是上面所寫的步驟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");
複製代碼
下面我將介紹個具體的例子,讓沒用過Retrofit的先熟悉下Retrofit如何使用json
public interface GetApi {
/** * 獲取用戶信息 * @return * @Query 註解 */
@GET("getUserInfo")
Call<UserInfo> getUserInfo(@Query("id") String userId);
}
複製代碼
這個@Query註解是什麼能夠先不用管,下面會詳細講解。後端
UserInfo是咱們獲得返回數據的數據Bean類api
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類
private GetApi getApi;
getApi = retrofit.create(GetApi.class);
複製代碼
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網絡請求接口中主要有哪些註解。
baseUrl爲:http://mock-api.com/2vKVbXK8.mock/
訪問地址
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
訪問地址
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);
}
});
複製代碼
訪問地址
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類時能夠用這個,這樣,咱們能夠經過上述字符串的形式獲取到返回的內容。
訪問地址
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這裏寫什麼均可以,沒有以/
結尾也能夠
靜態添加頭部信息:包含添加單個頭部、添加多個頭部
經過@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();
複製代碼
模客後臺
動態添加單個頭部信息
訪問地址
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的信息。
動態添加多個頭部信息
訪問地址
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中
對比着Get請求中的註解,Post請求中的註解就很好記了。
@Field 對應 @Query
@FieldMap 對應 @QueryMap
@Body 對應 @Url
注意
在Post請求中,儘可能不要使用@Query和@QueryMap,由於它傳入的參數是直接拼接在url上的,不安全,而@Field和@FieldMap是寫入到Body中的。
@FormUrlEncoded
用於修飾@Field
註解和@FieldMap
註解,將會自動將請求參數的類型調整爲
application/x-www-form-urlencoded
訪問地址
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後面
這裏是根據咱們設立的規則來進行匹配的,固然咱們也能夠選擇文本或其餘的方式進行匹配。
訪問地址
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.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 複製代碼
這兩個註解和文件上傳相關,在後面的文章中會進行詳細講解。
訪問地址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
複製代碼
以上就是關於Retrofit的一些註解的基本使用介紹,具體代碼見Github.
爲了簡便觀察,文章中只是使用了一個註解來創建接口,其實在實際使用時,能夠多個註解連用,例以下面所示:
@GET("api/{param}/getUserInfo")
Call<UserInfo> getUserInfo(@Path("params") String param, @Query("id") String userId);
複製代碼
具體怎麼結合仍是要根據實際項目提供的url來使用。以上就是所有內容,能力有限,不對的地方還望指出,有幫助的話還望點個start,下篇文章見。