Retrofit是現(xiàn)在十分流行的網(wǎng)絡(luò)請求庫,底層封裝了OkHttp肛根,實現(xiàn)了JSON和POJO的互相轉(zhuǎn)換像鸡,網(wǎng)絡(luò)請求回來直接是對象活鹰,簡化業(yè)務(wù)邏輯,用起來十分爽坟桅。
本文將會簡單介紹下Retrofit的使用方法华望,主要描述下自己寫的一個通用網(wǎng)絡(luò)請求模塊。
配置Retrofit
在build.gradle中添加依賴引入Retrofit仅乓,目前最新版本是2.1.0:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
對Json的序列化和反序列化赖舟,Retrofit提供了gson、jackson等多種轉(zhuǎn)換器夸楣。我用的是gson宾抓,需要額外添加依賴:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
創(chuàng)建Retrofit對象用的是Builder模式,同時可以設(shè)置底層的OkHttpClinet參數(shù)豫喧。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.addNetworkInterceptor(new StethoInterceptor())
.connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mHost)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
- LoggingInterceptor請求攔截器石洗,后面會介紹;
- Stetho是Facebook出品的Android可視化工具紧显,利用Chrome Developer Tools提供sqlit讲衫、preference、network等操作孵班,推薦去了解涉兽;
- GsonConverterFactory是上面講的Json轉(zhuǎn)換器,如果要對Json做特別的處理篙程,可以在create()傳入自定義Gson枷畏;
請求api
請求api定義在interface,下面是用于登錄的Post請求例子虱饿,返回值是類似于OkHttp的call拥诡。
@FormUrlEncoded
@POST("/api/login/")
Call<LoginResponse> doLoginIn(@FieldMap() TreeMap<String, String> paramMap);
入?yún)⑿问娇梢杂卸喾N触趴,提供對請求的不同處理,詳細可以查官網(wǎng)渴肉。
- @Query冗懦、@QueryMap:get請求的query參數(shù)
- @File、@FieldMap:form-url-encoded參數(shù)
- @Part:文件
- @Url:可傳入完整url
發(fā)出一個請求
獲得Retrofit對象和定義好請求的api之后宾娜,就可以發(fā)出網(wǎng)絡(luò)請求批狐,下面是同步和異步的例子。
ApiDefine service = retrofit.create(ApiDefine.class);
//同步
Call<LoginResponse> call = service.doLoginIn(paramMap);
retrofit2.Response<LoginResponse> response = call.execute();
LoginResponse loginResponse = response.body().
//異步
call.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, retrofit2.Response<LoginResponse> response) {
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
paramMap是一個Map前塔,請求用到的參數(shù)都放在里面。使用execute()發(fā)出同步請求承冰,或者enqueue()發(fā)出異步請求华弓。響應(yīng)結(jié)果用response.body()獲取定義好的LoginResponse,Retrofit會自動將json字符串轉(zhuǎn)換進LoginResponse困乒。
通用的請求響應(yīng)結(jié)果
一般服務(wù)器會返回通用的請求結(jié)果和對應(yīng)的業(yè)務(wù)數(shù)據(jù)寂屏,可以考慮使用一個通用請求基類HttpResponse,里面定義固定的返回結(jié)果娜搂。
private int result;
private String message;
private long timestamp;
private T data;
重點是data這個泛型迁霎,支持不同接口返回不同的具體業(yè)務(wù)數(shù)據(jù),只要設(shè)置不同的響應(yīng)類就行百宇。相應(yīng)地考廉,登錄api修改如下:
@FormUrlEncoded
@POST("/api/login/")
Call<HttpResponse<LoginResponse>> doLoginIn(@FieldMap() TreeMap<String, String> paramMap);
發(fā)送方法修改為支持泛型:
private <T extends BaseBizResponse> HttpResponse<T> doSend(Call<HttpResponse<T>> call) throws Exception {
retrofit2.Response<HttpResponse<T>> response;
try {
response = call.execute();
} catch (Exception e) {
//throw Exception
}
if (response.isSuccessful()) {
return response.body();
} else {
//throw Exception
}
}
泛型T增加實現(xiàn)BaseBizResponse這個業(yè)務(wù)用的基類,里面可以定義一些公共變量或者方法携御。
RxJava提供異步處理
自己開線程處理網(wǎng)絡(luò)請求是可以昌粤,但不如用專門的異步處理工具。RxJava是一個提供異步的啄刹、響應(yīng)式編程的庫涮坐,入門有點難度,但和Retrofit配合十分合適誓军。
public <T extends BaseBizResponse> Observable<T> send(final Call<HttpResponse<T>> call, Scheduler subscribeScheduler, Scheduler observeScheduler) {
return Observable.create(new Observable.OnSubscribe<HttpResponse<T>>() {
@Override
public void call(Subscriber<? super HttpResponse<T>> subscriber) {
HttpResponse<T> httpResponse = doSend(call);
subscriber.onNext(httpResponse);
}
}).map(new Func1<HttpResponse<T>, T>() {
@Override
public T call(HttpResponse<T> httpResponse) {
return dealHttpResponse(call, httpResponse);
}
}).subscribeOn(subscribeScheduler)
.observeOn(observeScheduler);
}
subscribeOn()指定網(wǎng)絡(luò)請求運行在什么線程袱讹,可以新建一個線程或者使用線程池;observeOn()指定網(wǎng)絡(luò)請求完成后在什么線程觀察執(zhí)行結(jié)果昵时,可以指定回到Android主線程捷雕。
send方法返回Observable,這是一個可以被觀察的對象债查。觀察結(jié)果時非区,調(diào)用subscribe可以指定三種Action,分別對應(yīng)onNext盹廷,onError征绸,onComplete,這里使用了onNext和onError,處理成功和失敗兩種情況管怠。繼承Action1實現(xiàn)SuccessAction和FailAction淆衷,就算不懂RxJava,也可以照葫蘆畫瓢調(diào)用網(wǎng)絡(luò)請求渤弛。
observable.subscribe(new SuccessAction<LoginResponse>() {
@Override
public void call(LoginResponse loginResponse) {
}
}, new FailAction<Throwable>() {
@Override
public void call(Throwable throwable) {
}
});
對于服務(wù)器返回的結(jié)果祝拯,往往更專注于業(yè)務(wù)數(shù)據(jù),所以加了一個步驟她肯,將HttpResponse<T>轉(zhuǎn)換為T佳头,只留下業(yè)務(wù)響應(yīng)類。并且晴氨,將服務(wù)器報錯的請求直接拋出異常康嘉,由FailAction處理。
調(diào)用dealHttpResponse()用到了map()方法籽前,這是RxJava一個操作符亭珍,用于對對象的轉(zhuǎn)換。
private <T extends BaseBizResponse> T dealHttpResponse(Call<HttpResponse<T>> call, HttpResponse<T> httpResponse) {
if (httpResponse.getResult() != RESPOND_RESULT_OK) {
//throw exception;
}
return (T) httpResponse.getData();
}
本文沒有詳細介紹RxJava枝哄,但非常推薦你去深入學(xué)習(xí)肄梨。一旦你弄懂RxJava,你會發(fā)現(xiàn)它真的太好用了挠锥。RxJava代碼如果改用lambda众羡,會更加簡潔精妙。
請求攔截
Retrofit的請求攔截使用OkHttp里面的Interceptor瘪贱,得到Request和Response后就可以做各種自定義操作纱控。比如想獲取每個請求的響應(yīng)時間,可以這樣實現(xiàn):
public static class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
LogUtils.d(String.format("HTTP響應(yīng)請求 %s %s %.1fms", response.request().url(), response.request().method(), time));
return response;
}
}
文件下載
請求文件的下載菜秦,基本方法差不多甜害,api定義改成傳入url,返回ResponseBody對象球昨。
@GET
@Streaming
Call<ResponseBody> download(@Url String url);
最終可以從ResponseBody對象獲得InputStream尔店,然后按照合適的方法寫入磁盤,這里不貼代碼了主慰。
retrofit2.Response<ResponseBody> retrofitResponse = call.execute();
InputStream inputStream = retrofitResponse.body().byteStream();
總結(jié)
Retrofit+RxJava十分好用嚣州,學(xué)Android的一定要學(xué)習(xí)下。我一直在改進這個網(wǎng)絡(luò)請求模塊共螺,有好的建議就告訴我啦该肴。