Retrofit--相信大家都或多或少的聽過和用過了蒿囤,不知道是什么的證明你已經(jīng)out了~我使用和研究Retrofit也有一段時間了守谓,所以準(zhǔn)備記錄一下自己使用的一些成果吕世。這篇將會介紹Retrofit的簡單配置和使用翻翩。
注:本系列Retrofit版本為2.1.0檐盟,OkHttp版本為3.4.1褂萧;本系列的接口均為非RESTful接口
Retrofit初識
1.HTTP請求方法和簡單的RESTful
Retrofit支持RESTful ,先來簡單的說一下RESTful接口(由于我自己也對RESTful一臉懵逼葵萎,所以請小伙伴們自行Google了解更多)导犹。首先在這里先來說一下HTTP的請求方法,HTTP請求方法包含get羡忘、post谎痢、delete、put卷雕、head节猿、patch、trace、options總共8種滨嘱。除get外峰鄙,其他6種都是基于post方法衍生的,最常見的是get和post太雨,而put吟榴、delete、post囊扳、get這四種最重要吩翻,分別對應(yīng)數(shù)據(jù)庫的增刪改查。
我們先來看一下比較常見的接口地址:
對學(xué)生信息進(jìn)行操作:1.查詢學(xué)生數(shù)量 2.創(chuàng)建新學(xué)生 3.修改學(xué)生信息 4.刪除學(xué)生锥咸。
請求方法 | 接口地址 | 接口說明 |
---|---|---|
get | /api/student/index | 查詢接口 |
post | /api/student/ + 參數(shù) | 創(chuàng)建接口 |
post | /api/student/update + 參數(shù) | 修改接口 |
post | /api/student/delete + 參數(shù) | 刪除接口 |
而如果我們用了RESTful API就會變成這樣:
請求方法 | 接口地址 | 接口說明 |
---|---|---|
get | /api/student/index | 查詢接口 |
post | /api/student/ + 參數(shù) | 創(chuàng)建接口 |
put | /api/student/ + 參數(shù) | 修改接口 |
delete | /api/student/ + 參數(shù) | 刪除接口 |
大家是不是也看出兩者的區(qū)別了狭瞎?修改跟刪除直接用HTTP的請求方法(Method)來指定,雖然url 一樣搏予,但仍然可以知道你的動作脚作。這就是所謂的RESTful 概念(這部分出自百萬講師stormzhang,感謝張哥帶我們飛~)
2.開啟Retrofit旅程
導(dǎo)入Retrofit:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
Retrofit通過接口來管理HTTP API缔刹,那么首先我們先定義一個API的接口:
public interface RetrofitApi{
@GET("public")
Call<BaseResult<User>> getUser();
}
然后通過Retrofit.Builder獲取到Retrofit實(shí)例,并通過create(clazz)方法獲取到我們剛才創(chuàng)建的RetrofitApi接口實(shí)例:
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("http://192.168.1.79:8080/")
.build();
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
有了RetrofitApi實(shí)例之后劣针,我們就可以在需要網(wǎng)絡(luò)請求的地方調(diào)用了:
Call<BaseResult<User>> userCall=retrofitApi.getUser();
以上是利用Retrofit向http://192.168.1.79:8080/public接口發(fā)送一個get請求校镐,獲取用戶信息。
注:baseUrl("")中的url必須以'/'結(jié)尾捺典,否則會報(bào)異常鸟廓;@GET("public")中的url如果是需要拼接在baseUrl之后的則不要以‘/’開頭
Retrofit的注解
Retrofit中有很多注解,這些注解總共分三類:HTTP請求方法襟己、標(biāo)記類引谜、參數(shù)類
1.HTTP請求方法注解
Retrofit支持八種HTTP請求方法注解,分別是:GET擎浴,POST员咽,PUT,DELETE贮预,HEAD贝室,PATCH,OPTIONS仿吞,HTTP滑频,其中前7種分別對應(yīng)HTTP請求方法(見Retrofit初識小節(jié)1),而HTTP注解可自定義請求方法唤冈,也就是說可以替換前面七種方法峡迷。
-
GET:對應(yīng)HTTP的get請求方法
寫法:
@GET("public") Call<BaseResult<List<User>>> getUser();
-
POST:對應(yīng)HTTP的post請求方法
寫法:
@POST("User") Call<BaseResult<String>> addUser();
-
PUT:對應(yīng)HTTP的put請求方法
寫法:
@PUT("User") Call<BaseResult<String>> updateUser();
-
DELETE:對應(yīng)HTTP的delete請求方法
寫法:
@DELETE("User") Call<BaseResult<String>> deleteUser();
HEAD:對應(yīng)HTTP的head請求方法
PATCH:對應(yīng)HTTP的patch請求方法
OPTIONS:對應(yīng)HTTP的options請求方法
-
HTTP:可替換以上七種,也可以擴(kuò)展請求方法
寫法:
/** * method 表示請的方法你虹,不區(qū)分大小寫 * path表示路徑 * hasBody表示是否有請求體 */ @HTTP(method = "get", path = "public", hasBody = false) Call<BaseResult<List<User>>> getUser();
2.標(biāo)記類注解
Retrofit支持三種標(biāo)記類注解绘搞,分別是:FormUrlEncoded彤避、Multipart、Streaming看杭。
-
FormUrlEncoded:指請求體是一個Form表單忠藤,Content-Type=application/x-www-form-urlencoded,需要和參數(shù)類注解@Field楼雹,@FieldMap搭配使用(詳見下節(jié))
寫法:
@FormUrlEncoded @POST("public") Call<BaseResult> addUser(@Field("userName") String userName);
-
Multipart:指請求體是一個支持文件上傳的Form表單模孩,Content-Type=multipart/form-data,需要和參數(shù)類注解@Part贮缅,@PartMap搭配使用(詳見下節(jié))
寫法:
@Multipart @POST("public") Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
-
Streaming:指響應(yīng)體的數(shù)據(jù)以流的形式返回榨咐,如果不使用默認(rèn)會把數(shù)據(jù)全部加載到內(nèi)存,所以下載文件時需要加上這個注解
寫法:
@Streaming @GET("download") Call<ResponseBody> downloadFile();
3.參數(shù)類注解
-
Headers:添加請求頭谴供,作用于方法
寫法:
@Headers("Cache-Control: max-age=640000") @GET("public") Call<BaseResult<List<User>>> getUser();
或
@Headers({ "Cache-Control: max-age=640000" "User-Agent: Retrofit-Sample-App" }) @GET("public") Call<BaseResult<List<User>>> getUser();
?
-
Header:用于動態(tài)添加頭部块茁,作用于方法參數(shù)
寫法:
@GET("public") Call<BaseResult<List<User>>> getUser(@Header("Token") String token);
-
Body:用于非表單請求體,作用于方法參數(shù)
寫法:
@POST("user") Call<BaseResult<String>> addUser(@Body User user);
-
Url:用于動態(tài)改變Url桂肌,作用于方法參數(shù)
寫法:
@GET("public") Call<BaseResult<List<User>>> getUser(@Url String url);
請求的時候数焊,url會替換掉public
-
Path:用于替換請求地址,作用于方法參數(shù)
寫法:
@GET("{path}") Call<BaseResult<List<User>>> getUser(@Path("path") String path);
-
Field:用于表單字段參數(shù)崎场,(需要配合FormUrlEncoded使用)作用于方法參數(shù)
寫法:
@FormUrlEncoded @POST("public") Call<BaseResult> addUser(@Field("userName") String userName);
-
FieldMap:用于表單字段參數(shù)佩耳,接收Map實(shí)現(xiàn)多個參數(shù),(需要配合FormUrlEncoded使用)作用于方法參數(shù)
寫法:
@FormUrlEncoded @POST("public") Call<BaseResult> addUser(@FieldMap Map<String,String> fieldMap);
-
Part:用于表單字段參數(shù)谭跨,適用于文件上傳干厚,(需要配合Multipart使用)作用于方法參數(shù)
寫法:
@Multipart @POST("public") Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
-
PartMap:用于表單字段參數(shù),適用于文件上傳螃宙,(需要配合Multipart使用)作用于方法參數(shù)
寫法:
@Multipart @POST("public") Call<BaseResult> uploadFile(@PartMap Map<String,RequestBody> RequestBodyMap);
-
Query:用于條件字段參數(shù)蛮瞄,作用于方法參數(shù)
寫法:
@GET("public") Call<BaseResult<List<User>>> getUser(@Query("userId") String userId);
-
QueryMap:用于條件字段參數(shù),作用于方法參數(shù)
寫法:
@GET("public") Call<BaseResult<List<User>>> getUser(@QueryMap Map<String,String> map);
注:如果使用Post請求方式谆扎,建議使用Field或FieldMap+FormUrlEncoded傳遞參數(shù)挂捅,雖然Query或QueryMap也可以實(shí)現(xiàn),但是Query或QueryMap都是將參數(shù)拼接在url后面的堂湖,而@Field或@FieldMap傳遞的參數(shù)時放在請求體的
Retrofit的配置
1.為Retrofit添加Converter
Retrofit中提供了Converter的概念籍凝,直譯為轉(zhuǎn)換器,Retrofit正常請求下來后苗缩,響應(yīng)體為ResponseBody類型饵蒂,我們需要將ResponseBody解析后才能得到我們想要的數(shù)據(jù),那么如果我們想要直接在響應(yīng)的時候拿到我們想要的數(shù)據(jù)怎么辦呢酱讶?這時候我們就需要Converter來幫我們進(jìn)行轉(zhuǎn)換了退盯。Retrofit提供了幾個轉(zhuǎn)換器,如下表:
依賴庫 | Gradle引用 | 來源 |
---|---|---|
Gson | com.squareup.retrofit2:converter-gson | 官方 |
Jackson | com.squareup.retrofit2:converter-jackson | 官方 |
Moshi | com.squareup.retrofit2:converter-moshi | 官方 |
Protobuf | com.squareup.retrofit2:converter-protobuf | 官方 |
Wire | com.squareup.retrofit2:converter-wire | 官方 |
Simple Framework | com.squareup.retrofit2:converter-simpleframework | 官方 |
Scalars | com.squareup.retrofit2:converter-scalars | 官方 |
LoganSquare | com.github.aurae.retrofit2:converter-logansquare | 第三方 |
FastJson | org.ligboy.retrofit2:converter-fastjson 或org.ligboy.retrofit2:converter-fastjson-android | 第三方 |
我們用Gson來介紹一下如何使用,首先引入Gson的Converter:
com.squareup.retrofit2:converter-gson:2.1.0
然后通過Retrofit.Builder()配置添加Converter:
Retrofit retrofit=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://192.168.1.79:8080/")
.build();
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
接著讓我們來測試一下吧:
接口返回?cái)?shù)據(jù)格式為:
{
"status": "1",
"message": "success",
"data": {
"name": "zyyoona7",
"age": "18",
"height": "180cm"
}
}
兩個實(shí)體類分別為BaseResult和User:
//BaseResult類
public class BaseResult<T> {
public static final int FAILURE = 0; // 失敗
public static final int SUCCESS = 1; // 成功
private int status; // 返回狀態(tài):0 失敗 1 成功
private String message; // 返回信息
private T data; // 包裝的對象
//...省略getter setter
}
//User類
public class User implements Parcelable {
private String name;
private int age;
private String height;
//省略getter setter
}
請求接口:
@GET("public")
Call<BaseResult<User>> getUser();
代碼調(diào)用:
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
Call<BaseResult<User>> userCall=retrofitApi.getUser();
userCall.enqueue(new Callback<BaseResult<User>>() {
@Override
public void onResponse(Call<BaseResult<User>> call, Response<BaseResult<User>> response) {
//直接解析出我們想要的數(shù)據(jù)
}
@Override
public void onFailure(Call<BaseResult<User>> call, Throwable t) {
}
});
2.為Retrofit添加RxJava支持
支持RxJava簡直就是Retrofit的大招哇渊迁,用起來超級酷慰照,如果你對RxJava還不了解請移步RxJava學(xué)習(xí)資料鏈接,是時候用起RxJava了琉朽。我們來配置一下毒租,使Retrofit支持RxJava:
首先導(dǎo)入:
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
然后通過Retrofit.Builder配置:
Retrofit retrofit=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
//RxJava支持
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl("http://192.168.1.79:8080/")
.build();
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
接著接口的返回值需要轉(zhuǎn)變一下:
@GET("public")
Observable<BaseResult<User>> getUser();
這時候就可以開車了:
retrofitApi.getUser()
.flatMap(new Func1<BaseResult<User>, Observable<User>>() {
@Override
public Observable<User> call(BaseResult<User> userBaseResult) {
return Observable.just(userBaseResult.getData());
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<User>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(User user) {
Log.e(TAG, "onNext: " + user);
}
});
3.為Retrofit添加日志攔截器
Retrofit是很強(qiáng)大,但是調(diào)試的時候想要看到請求和響應(yīng)的信息怎么辦呢箱叁?Retrofit是一個封裝墅垮,它依賴了OkHttp作為客戶端,從源碼中可以看出:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//...省略
}
從方法中看出耕漱,如果callFactory為null則會創(chuàng)建新的OkHttpClient算色,而且在Builder中提供了client()方法,可以讓我們重新設(shè)置Client螟够。這樣我們可以通過給OkHttpClient添加攔截器來實(shí)現(xiàn)打印日志灾梦。
官方給我們提供了一個攔截器:
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
在Retrofit2.1.0的版本中,如果我們的項(xiàng)目不導(dǎo)入OkHttp妓笙,默認(rèn)將會導(dǎo)入OkHttp-3.3.0和okio-1.8.0若河,我們可以導(dǎo)入最新的OkHttp:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
創(chuàng)建HttpLoggingInterceptor對象:
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
打印日志有四個級別:
- Level.BODY:打印請求頭,請求體和響應(yīng)頭寞宫,響應(yīng)體的所有內(nèi)容
- Level.HEADERS:打印請求和響應(yīng)的頭部信息
- Level.BASIC:打印基本信息
- Level.NONE:無打印
配置到Retrofit中:
Retrofit retrofit=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//配置OkHttpClient
.client(new OkHttpClient().newBuilder().addInterceptor(loggingInterceptor).build())
.baseUrl("http://192.168.1.79:8080/")
.build();
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
這樣我們就可以暢爽的看日志信息了~~~
4.為Retrofit添加請求頭
在項(xiàng)目中或多或少都會用到請求頭牡肉,比如登錄的token之類的,具體看服務(wù)器端如何規(guī)定淆九,上面再介紹注解的時候我們已經(jīng)看到了可以通過@Headers
或者@Header
來添加頭部信息(具體寫法請看Retrofit的注解第3小節(jié))。這兩種寫法只是給特定的接口添加毛俏,如果接口多的話那手指就得抽筋了炭庙,有沒有統(tǒng)一添加頭部的方法呢?答案是肯定的煌寇。依然通過給OkHttp添加攔截器的方式焕蹄。
自定義HeaderInterceptor:
public class HeaderInterceptor implements Interceptor {
private Map<String, String> headers = new HashMap<>();
public HeaderInterceptor(Map<String, String> headers) {
this.headers = headers;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
for (String key : headers.keySet()) {
builder.addHeader(key, headers.get(key));
}
Request request = builder.build();
return chain.proceed(request);
}
然后就可以愉快的使用了:
Map<String,String> headerMap=new HashMap<>();
headerMap.put("token","123456");
//...more
HeaderInterceptor headerInterceptor=new HeaderInterceptor();
Retrofit retrofit=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//配置OkHttpClient
.client(new OkHttpClient().newBuilder()
.addInterceptor(loggingInterceptor)
.addInterceptor(headerInterceptor)
.build())
.baseUrl("http://192.168.1.79:8080/")
.build();
RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);
更多使用可以猛戳:https://github.com/square/retrofit/wiki/Retrofit-Tutorials
Demo努力趕制中...其他篇幅努力編寫中...
參考
如何使用Retrofit請求非Restful API
你真的會用Retrofit2嗎?Retrofit2完全教程
Retrofit官網(wǎng)
Retrofit Wiki