1.背景
1)项目中原来使用了 AsyncHttpClient框架。这套框架不满足 https + sni 的需要,需要改造。
2)具体的页面中,有约100个接口,在200+ 处使用了AsyncHttpClient,格式类似于
RequestParams params = new RequestParams();
params.put("userId", hostUserId);
params.put(...);
new AsyncHttpClient().getUserList(params, new TextHttpResponseHandler(){
@override
public abstract void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable){
// 具体实现
}
@override
public abstract void onSuccess(int statusCode, Header[] headers, String responseString){
// 具体实现
}
});
3)接口返回的数据格式不尽相同
4)每个接口的完整url(除接口参数外),包括方法名,都可以通过url管理类获取,类似于
String url_get_user_list = UrlHelper.get_user_list => http://xxx.yyy.com/api?aaa/bbb?cc=12&dd=dsd&method=app.user.list
2.目标
1)引入retrofit 支持https+sni
2)构建合适的框架,以简单快速的替换200+ 处的 AsyncHttpClient 的使用
具体实现
1.定义一个类似于TextHttpResponseHandler的回调接口,剥离回调接口与具体网络框架的耦连
public abstract class TextCallback {
public abstract void onFailure(int statusCode, okhttp3.internal.http2.Header[] headers, String responseString, Throwable throwable);
public abstract void onSuccess(int statusCode, okhttp3.internal.http2.Header[] headers, String responseString);
}
这里的Header属于什么类无所谓,因为页面的逻辑处理中并没有用到header
2.定义一个中间管理类和公共方法,连接具体页面与实际的网络框架,使页面与网络框架解耦,类似于
public class NetManager {
public static void go(Object tag, int methodType, String url, Map<String, Object> params, int time, TextCallback callback){
// 这里访问实际的网络框架类
RetrofitHelper.enqueue(tag, methodType, url, params, callback);
}
}
这个公共方法只接收如下参数
tag 用于在页面销毁时取消tag对应的网络请求
methodType 方法类型,如get post等等
url 完整的url,包含了方法名
params 接口方法规定的参数
TextCallback 回调对象
3.定义retrofitservice
这里的需求是简单快速的替换约100个接口,所以不能像如下一样,给每个接口定义一种方法,这样太麻烦
@GET()
Call<List<User>> getUserList(@Query("userId") String hostUserId, @Query("pageNumber") int pageNumber, @Query("pageNumber") int pageNumber);
@GET()
Call<UserProfile> getUserProfile(@Query("userId") String userId);
所以,写成如下格式
@GET()
Call<ResponseBody> getWithMap(@Url String url, @QueryMap Map<String, Object> param);
@FormUrlEncoded
@POST()
Call<ResponseBody> postWithMap(@Url String url, @FieldMap Map<String, Object> param);
为什么回调类型写成ResponseBody:因为在retrofit中使用GsonConverterFactory时,这转换工厂会把如下格式的数据
{"userId":"ssde4", "userPhone":null,...}
转换为
{"userId":"ssde4",...}
自动去掉为null的字段的key。而页面在解析时获取userPhone,是这么写的
String s = {"userId":"ssde4",...}
new JsonObject(s).getString("userPhone")
会导致 JSONObject exception: No value for userPhone。这种写法在项目已有的代码中出现多处,为了避免一一修改,因此没有在retrofit的okhttpclient中使用任何converterFactory,直接回调ResponseBody
4.定义实际使用的retrofit工具类,类似于
public class RetrofitHelper {
public static final int METHOD_GET = 1;
public static final int METHOD_POST = 2;
public static void enqueue(Object tag, int methodType,String fullUrl, Map<String, Object> param, final TextCallback callback){
OkHttpClient.Builder okClientBuilder = new OkHttpClient
.Builder()
.addInterceptor(new MyLogInterceptor());
List<Interceptor> interceptors = new ArrayList<>();
if(XXX){
interceptors.add(new XXXInterceptor());
}
for (Interceptor interceptor : interceptors){
okClientBuilder.addInterceptor(interceptor);
}
RetrofitService retrofitService = new Retrofit.Builder()
.client(okClientBuilder.build())
.baseUrl("因为使用了@url,所以这里的baseurl随便写")
.build()
.create(RetrofitService.class);
Call<ResponseBody> call = null;
if(methodType == METHOD_GET){
call = retrofitService.getWithMap(fullUrl, param);
}else if(methodType == METHOD_POST){
call = retrofitService.postWithMap(fullUrl, param);
}
if(call != null){
CallContainer.attachTag(tag, call); // 保存tag与call的关联关系
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
ResponseBody body = response.body();
if(body == null){
String msg = "";
try{
msg = response.errorBody().string();
}catch (IOException e){
LogUtil.debug("enqueue", "" + e.getMessage());
}
callback.onFailure(response.raw().code(), null, msg, new XXXException("AAA"));
}else {
try{
String rawString = body.string();
String newRes = preHandleResult(response.raw().request().url().toString(), rawString);
callback.onSuccess(response.raw().code(), null, newRes);
} catch (IOException e) {
e.printStackTrace();
callback.onFailure(XXX, null, "", e);
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
LogUtil.debug("onFailure", "" + t.getMessage());
callback.onFailure(YYY, null, "", t);
}
});
}
}