Retrofit配置及各情况处理
2018-12-06 本文已影响267人
打酱油的日光灯
打造终极MVP+Retrofit2+okhttp3+Rxjava2网络请求,开发实用,简约,由于篇幅字数原因 本章讲解Retrofit配置及各种处理情况
抓住人生中的一分一秒,胜过虚度中的一月一年!
前言
目前较火的网络请求其中有MVP+Retrofit2+okhttp3+Rxjava2,于是我也加入了使用行列,在网上找了许多案例,实际代码开发中解决了一些所谓的坑,总结了些内容与大家共享一下,有不足的地方希望大家提出我将进行再次完善。
实现目标
1、Retrofit创建
2、Retrofit实现Cookie自动化管理
3、Retrofit,Gson解析,请求返回的类型不统一,假如double返回的是null
4、请求参数日志打印
5、统一请求参数添加到请求头中
6、统一请求参数添加到请求body中
7、缓存的拦截器
8、BaseUrl动态切换
1、Retrofit创建
public class ApiRetrofit {
private static final String BASE_SERVER_URL = "www.baidu.com";
private static final int DEFAULT_TIMEOUT = 15;
private static ApiRetrofit apiRetrofit;
private Retrofit mRetrofit;
private ApiServer mApiServer;
private String TAG = "ApiRetrofit %s";
public static ApiRetrofit getInstance() {
if (apiRetrofit == null) {
synchronized (Object.class) {
if (apiRetrofit == null) {
apiRetrofit = new ApiRetrofit();
}
}
}
return apiRetrofit;
}
public ApiServer getApiService() {
return mApiServer;
}
public ApiRetrofit() {
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);//错误重联
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_SERVER_URL)
.addConverterFactory(MyGsonConverterFactory.create())
//支持RxJava2
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClientBuilder.build())
.build();
mApiServer = mRetrofit.create(ApiServer.class);
}
}
2、Retrofit实现Cookie自动化管理
3、Retrofit,Gson解析,请求返回的类型不统一,假如double返回的是null
4、请求参数日志打印
1.第一种办法,依赖第三方库
compile 'com.squareup.okhttp3:logging-interceptor:3.9.1'
配置信息如下
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
if(BuildConfig.DEBUG){
//显示日志
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
}else {
logInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
}
httpClientBuilder.addInterceptor(logInterceptor);
2.第二种办法,拦截器拦截(个人推荐第二种,可控性高)
给大家推荐一个打印日志库,很漂亮的日志结构
implementation 'com.orhanobut:logger:2.2.0'
/**
* 请求访问quest 打印日志
* response拦截器
*/
private Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.currentTimeMillis();
Response response = chain.proceed(chain.request());
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
MediaType mediaType = response.body().contentType();
String content = response.body().string();
Logger.wtf(TAG, "----------Request Start----------------");
printParams(request.body());
Logger.e(TAG, "| " + request.toString() + "===========" + request.headers().toString());
Logger.json(content);
Logger.e(content);
Logger.wtf(TAG, "----------Request End:" + duration + "毫秒----------");
return response.newBuilder()
.body(ResponseBody.create(mediaType, content))
.build();
}
};
/**
* 请求参数日志打印
*
* @param body
*/
private void printParams(RequestBody body) {
if (body != null) {
Buffer buffer = new Buffer();
try {
body.writeTo(buffer);
Charset charset = Charset.forName("UTF-8");
MediaType contentType = body.contentType();
if (contentType != null) {
charset = contentType.charset(UTF_8);
}
String params = buffer.readString(charset);
Logger.e(TAG, "请求参数: | " + params);
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后在httpClientBuilder中添加拦截
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder
//打印日志拦截
.addInterceptor(interceptor)
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);//错误重联
5、统一请求参数添加到请求头中
/**
* 需要头可以添加 请求头
*/
public class HeadUrlInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request()
.newBuilder()
// .addHeader("Content-Type", "text/html; charset=UTF-8")
// .addHeader("Vary", "Accept-Encoding")
// .addHeader("Server", "Apache")
// .addHeader("Pragma", "no-cache")
// .addHeader("Cookie", "add cookies here")
// .addHeader("Cookie", cookie_name + "=" + cookie_value)
.addHeader("XX-Token", App.mToken)
.addHeader("XX-Device-Type", "android")
// .addHeader("_identity", cookie_value)
.build();
return chain.proceed(request);
}
}
然后在httpClientBuilder中添加拦截
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder
//添加参数到请求头
.addInterceptor(new HeadUrlInterceptor())
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);//错误重联
6、统一请求参数添加到请求body中
/**
* 获取HTTP 添加公共参数的拦截器
* 暂时支持get、head请求&Post put patch的表单数据请求
*
* @return
*/
public class HttpParamsInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.method().equalsIgnoreCase("GET") || request.method().equalsIgnoreCase("HEAD")) {
HttpUrl httpUrl = request.url().newBuilder()
.addQueryParameter("version", "1.1.0")
.addQueryParameter("devices", "android")
.build();
request = request.newBuilder().url(httpUrl).build();
} else {
RequestBody originalBody = request.body();
if (originalBody instanceof FormBody) {
FormBody.Builder builder = new FormBody.Builder();
FormBody formBody = (FormBody) originalBody;
for (int i = 0; i < formBody.size(); i++) {
builder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
}
FormBody newFormBody = builder
.addEncoded("version", "1.1.0")
.addEncoded("devices", "android")
.build();
if (request.method().equalsIgnoreCase("POST")) {
request = request.newBuilder().post(newFormBody).build();
} else if (request.method().equalsIgnoreCase("PATCH")) {
request = request.newBuilder().patch(newFormBody).build();
} else if (request.method().equalsIgnoreCase("PUT")) {
request = request.newBuilder().put(newFormBody).build();
}
} else if (originalBody instanceof MultipartBody) {
}
}
return chain.proceed(request);
}
}
然后在httpClientBuilder中添加拦截
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder
//添加参数到请求body
.addInterceptor(new HttpParamsInterceptor())
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);//错误重联
7、缓存的拦截器
/**
* 获得HTTP 缓存的拦截器
*
* @return
*/
public class HttpCacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 无网络时,始终使用本地Cache
if (!NetWorkUtils.isConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetWorkUtils.isConnected()) {
//有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
String cacheControl = request.cacheControl().toString();
return response.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma")
.build();
} else {
// 无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
return response.newBuilder()
//这里的设置的是我们的没有网络的缓存时间,想设置多少就是多少。
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
}
}
然后在httpClientBuilder中添加拦截
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder
.addInterceptor(new HttpCacheInterceptor())
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);//错误重联
8、BaseUrl动态切换
用了一个博客中民间大神的拦截动态替换baseUrl方法有点问题,我暂时用了一种简单粗暴方法
@FormUrlEncoded
@POST("http://www.baidu.com/api/user/edit?")
Observable<BaseModel<Object>> getEditInfo(@FieldMap HashMap<String, String> params);
上边的路径是我随便写的,post中写全路径,这个优先级最高,同时设置了baseUrl不受影响
给大家一个专门写动态替换baseUrl连接 传送门