最近几天都在看retrofit和okhttp这个开源网络库组合,现在来分享和大家一下。
首先引入依赖
如下:
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.0'
首先来看
- 1.
okhttp的Builder的 配置模式
OkHttpClient.Builder builder = new OkHttpClient.Builder();
/**
*设置缓存
*/
File cacheFile = new File(MyApplication.getInstance().getExternalCacheDir(), "AppCache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetworkUtils.isNetworkAvailable(MyApplication.getInstance())) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetworkUtils.isNetworkAvailable(MyApplication.getInstance())) {
int maxAge = 0;
// 有网络时 设置缓存超时时间0个小时
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("app")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.build();
} else {
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + "60 * 60 * 24 * 7")
.removeHeader("app")
.build();
ActivityUtils.toast(R.string.no_net_connect_txt);
}
return response;
}
};
builder.cache(cache).addInterceptor(cacheInterceptor);
/**
* 公共参数
*/
Interceptor addQueryParameterInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request request = null;
HttpUrl modifiedUrl = originalRequest.url().newBuilder()
.addQueryParameter("参数", "")
.build();
request = originalRequest.newBuilder().url(modifiedUrl).build();
return chain.proceed(request);
}
};
builder.addInterceptor(addQueryParameterInterceptor);
/**
* 设置头
*/
/**
* Log信息拦截器
*/
if (BuildConfig.DEBUG) {
// Log信息拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//设置 Debug Log 模式
builder.addInterceptor(loggingInterceptor);
}
/**
* 设置cookie
*/
/**
* 设置超时和重连
*/
//设置超时
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(10, TimeUnit.SECONDS);
builder.writeTimeout(10, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);//错误重连
OkHttpClient okHttpClient = builder.build();
然后是Retrofit配置
public static Retrofit retrofit = null;
public static Retrofit retrofit() {
if (retrofit == null) {
......//okhttp的配置放在这
retrofit = new Retrofit.Builder()
.baseUrl(ApiUrl.getHeadUrl())
.client(okHttpClient)
.addConverterFactory(JsonConverterFactory.create())//转换器
.build();
}
return retrofit;
}
这里注意一点 JsonConverterFactory.create()这个是自定义的转换器,如果不需要刻意直接使用GsonConverterFactory.create()。
当然在日常开发中系统给的转换器并不能给我们带来方便,所以我们必须
自定义转换器
。
public class JsonConverterFactory extends Converter.Factory {
public static JsonConverterFactory create() {
return new JsonConverterFactory();
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new JsonResponseBodyConverter<>(type);//响应
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new JsonRequestBodyConverter<>();//请求
}
}
接下来是请求响应
public class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
@Override
public RequestBody convert(T value) throws IOException {
return RequestBody.create(MEDIA_TYPE, value.toString());
}
}
下面最重要的来了。我个人认为这也是最核心的一个点,因为我的写法上的错误,导致我被这个问题困了很久。
public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Type type;
public JsonResponseBodyConverter(Type type) {
this.type = type;
}
/**
* 转换
*
* @param responseBody
* @return
* @throws IOException
*/
@Override
public T convert(ResponseBody responseBody) throws IOException {
BufferedSource bufferedSource = Okio.buffer(responseBody.source());
String tempStr = bufferedSource.readUtf8();
bufferedSource.close();
JSONObject jsonObject = null;
T t = null;
try {
jsonObject = new JSONObject(tempStr);
t = GsonHelper.getDeserializer().fromJson(jsonObject.getString("data"), type);
} catch (JSONException e) {
e.printStackTrace();
}
return t;
}
}
需要注意的是,**为了封装我老是想着把需要解析的类传入进去,其实不然,这里的这个T,就代表着这个类,结果输出t就可以了。
下面是我的错误代码**:
public T convert(ResponseBody responseBody) throws IOException {
BufferedSource bufferedSource = Okio.buffer(responseBody.source());
String tempStr = bufferedSource.readUtf8();
bufferedSource.close();
JSONObject jo = null;
Object jsonObject = null;
try {
jo = new JSONObject(tempStr);
jsonObject = new JSONObject(jo.getString("data"));
} catch (JSONException e) {
e.printStackTrace();
}
return (T) jsonObject;
}
看到了么,这里返回的数据类型被我弄成了JSONObject,当解析的数据是JSONObject是正确的,而一旦解析的数据是JSONArray时,就不正确了。引以为戒!!!
再来看我封装的
Call回调
public class BaseRequest<T> {
private Call<T> mCall;
public BaseRequest(Call call) {
mCall = call;
}
//异步请求
public void handleResponse(final ResponseListener listener) {
mCall.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.raw().code() == 200) {//200是服务器有合理响应
if (response.isSuccessful()) {
listener.onSuccess(response.body());
}
} else {
//失败响应
onFailure(call, new RuntimeException("response error,detail = " + response.raw().toString()));
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
if (t instanceof SocketTimeoutException) {
ActivityUtils.toast("连接超时!");
} else if (t instanceof ConnectException) {
ActivityUtils.toast("网络出错");
}
listener.onFail();
}
});
}
// 取消
public void cancel() {
mCall.cancel();
}
public interface ResponseListener<T> {
void onSuccess(T t);
void onFail();
}
}
然后
调取方法
new BaseRequest<Result>(AppClient.retrofit().create(ResultService.class)
.getResult(...)).handleResponse(baseResultResponseListener);
BaseRequest.ResponseListener<Result> baseResultResponseListener = new BaseRequest.ResponseListener<Result>() {
@Override
public void onSuccess(Result result) {
}
@Override
public void onFail() {
}
};
这样写好之后,你可以看看,是不是调取就方便些了呢。欢迎各位指正,谢谢