本文将围绕Retrofit的组装请求管理器、发起请求、请求响应的封装进行介绍。
以获取手机号码归属地的整个流程为例:
Get请求
请求API类,这个类等待Retrofit通过动态代理的方式将这个接口的方法以及对应得注解生成一个http请求,在把这个http请求交给OkHttp处理。
public interface HttpService {
@GET(GlobalVar.NetPorts.WEATHER)
Observable <HttpResult<PhoneLocalBean>> queryWeather(@QueryMap Map<String, String> options);
}
请求管理器
创建一个请求管理器用来配置Retrofit与OkHttp的基本属性。
public class HttpManager {
public static final String SERVER = GlobalVar.SERVER; //服务器根地址
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() {
//这里的存储位置只是简单获取,根据实际需要修改
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;
}
}
请求拦截器
用于对请求的发起与响应的拦截,这里我们可以增加统一的Header,客户端与服务端的加密验证也可以放在这里,网络缓存等等。
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())) {
//网络不可用
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())) { //如果网络可用
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");
}
}
发起请求
这里的addMainSubscription用于简化书写并统一管理发起的订阅,当Activity退出时统一取消订阅。
@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();
}
});
}
自定义请求响应回调
对响应数据成功失败的封装,而一般的数据返回格式基本分为:
1、状态码
2、提示信息
3、具体数据内容
具体数据体可以是集合也可以是对象,所以使用了泛型HttpResult<M>统一处理。这里定义的M一方面是告诉GSON我的子数据格式是什么,另一方面用于回调方法中返回对应得数据类型。
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("网络异常,请检查网络", 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);
}
}
}
结语
这里的代码都是结合具体项目来写的,虽然是抽出来的精简版但更容易读懂。我觉得直接看代码更容易理解一段代码的思想,所以大多都是以代码为主注释为辅。最后有哪些不足的地方也谢谢大家指出来~。