本文將圍繞Retrofit的組裝請求管理器适贸、發(fā)起請求佛析、請求響應(yīng)的封裝進(jìn)行介紹沿后。
以獲取手機(jī)號碼歸屬地的整個流程為例:
Get請求
請求API類刽锤,這個類等待Retrofit通過動態(tài)代理的方式將這個接口的方法以及對應(yīng)得注解生成一個http請求镊尺,在把這個http請求交給OkHttp處理。
public interface HttpService {
@GET(GlobalVar.NetPorts.WEATHER)
Observable <HttpResult<PhoneLocalBean>> queryWeather(@QueryMap Map<String, String> options);
}
請求管理器
創(chuàng)建一個請求管理器用來配置Retrofit與OkHttp的基本屬性并思。
public class HttpManager {
public static final String SERVER = GlobalVar.SERVER; //服務(wù)器根地址
private HttpService mHttpService;
private Retrofit mAdapter;
private static HttpManager instance;
private HttpManager() {
mAdapter = new Retrofit.Builder().baseUrl(SERVER).addConverterFactory(ScalarsConverterFactory.create()).addConverterFactory(GsonDConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(getBuilder().build()).build();
}
public static HttpManager getInstance() {
if (instance == null) {
instance = new HttpManager();
}
return instance;
}
public HttpService sendRequest() {
if (mHttpService == null) {
mHttpService = mAdapter.create(HttpService.class);
}
return mHttpService;
}
private OkHttpClient.Builder getBuilder() {
//這里的存儲位置只是簡單獲取庐氮,根據(jù)實際需要修改
File cacheFile = new File(BaseApplication.getContext().getCacheDir().getAbsolutePath(), "ShopHttpCache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 100);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new HttpCacheInterceptor());
builder.cache(cache);
builder.readTimeout(GlobalVar.READ_TIMEOUT, TimeUnit.SECONDS);
builder.connectTimeout(GlobalVar.CONNECT_TIMEOUT, TimeUnit.SECONDS);
builder.writeTimeout(GlobalVar.WRITE_TIMEOUT, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);
return builder;
}
}
請求攔截器
用于對請求的發(fā)起與響應(yīng)的攔截,這里我們可以增加統(tǒng)一的Header宋彼,客戶端與服務(wù)端的加密驗證也可以放在這里弄砍,網(wǎng)絡(luò)緩存等等。
public class HttpCacheInterceptor implements Interceptor {
private static final String TAG = "HttpManager";
@Override public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder().method(original.method(), original.body());
Headers.Builder hb = new Headers.Builder();
addHeader(hb);
if (!NetUtils.isConnected(BaseApplication.getContext())) {
//網(wǎng)絡(luò)不可用
requestBuilder.cacheControl(CacheControl.FORCE_CACHE);
} else {
requestBuilder.cacheControl(CacheControl.FORCE_NETWORK);
}
Request request = requestBuilder.headers(hb.build()).build();
Log.d(TAG, "地址:" + request.url());
try {
Response response = chain.proceed(request);
String cookie = response.headers().get("Set-Cookie");
if (NetUtils.isConnected(BaseApplication.getContext())) { //如果網(wǎng)絡(luò)可用
int maxAge = 60 * 3;
response = response.newBuilder().removeHeader("Pragma").header("Cache-Control", "public, max-age=" + maxAge).build();
} else {
int maxStale = 60 * 60 * 24;
response = response.newBuilder().removeHeader("Pragma").header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale).build();
}
return response;
} catch(Exception err) {
Log.e("HttpManager", "http=============" + err.getLocalizedMessage());
}
return null;
}
private void addHeader(Headers.Builder header) {
header.add("apikey", "8ca4b101096587f725ff69a07ff4d188");
}
}
發(fā)起請求
這里的addMainSubscription用于簡化書寫并統(tǒng)一管理發(fā)起的訂閱输涕,當(dāng)Activity退出時統(tǒng)一取消訂閱音婶。
@Override
public void queryWeather(String phone) {
Map < String, String > options = new HashMap < >();
options.put("phone", phone);
addMainSubscription(HttpManager.getInstance().sendRequest().queryWeather(options), new HttpResultCallBack<PhoneLocalBean> () {
@Override public void onResponse(PhoneLocalBean bean, int status) {
if (bean != null) {
mView.onUserLoadCompleted(bean);
} else {
mView.onUserLoadError();
}
}
@Override public void onErr(String err, int status) {
mView.showToast(err);
mView.onUserLoadError();
}
});
}
自定義請求響應(yīng)回調(diào)
對響應(yīng)數(shù)據(jù)成功失敗的封裝,而一般的數(shù)據(jù)返回格式基本分為:
1莱坎、狀態(tài)碼
2衣式、提示信息
3、具體數(shù)據(jù)內(nèi)容
具體數(shù)據(jù)體可以是集合也可以是對象檐什,所以使用了泛型HttpResult<M>統(tǒng)一處理碴卧。這里定義的M一方面是告訴GSON我的子數(shù)據(jù)格式是什么,另一方面用于回調(diào)方法中返回對應(yīng)得數(shù)據(jù)類型乃正。
public abstract class HttpResultCallBack<M> extends Subscriber <HttpResult<M>> {
public abstract void onResponse(M m, int status);
public abstract void onErr(String msg, int status);
@Override public void onCompleted() {}
@Override public void onError(Throwable e) {
if (e != null) {
if (e instanceof ResultException) {
ResultException err = (ResultException) e;
onErr(err.getErrMsg(), GlobalVar.RESULT_UNLOGIN);
} else {
onErr("網(wǎng)絡(luò)異常住册,請檢查網(wǎng)絡(luò)", GlobalVar.RESULT_UNLOGIN);
Log.d("HttpManager", "解析失敗==:" + e.getMessage());
}
}
onCompleted();
}
private void onHttpFail(String msg, int status) {
onErr(msg, status);
}
@Override public void onNext(HttpResult < M > result) {
String jsonResponse = new Gson().toJson(result);
Log.d("HttpManager", "返回ok==:" + jsonResponse);
if (result.getErrNum() == GlobalVar.RESULT_OK) {
onResponse(result.getRetData(), GlobalVar.RESULT_OK);
} else {
onHttpFail(result.getErrMsg(), GlobalVar.RESULT_UNLOGIN);
}
}
}
結(jié)語
這里的代碼都是結(jié)合具體項目來寫的,雖然是抽出來的精簡版但更容易讀懂瓮具。我覺得直接看代碼更容易理解一段代碼的思想荧飞,所以大多都是以代碼為主注釋為輔。最后有哪些不足的地方也謝謝大家指出來~名党。