package com.lzy.okgo.adapter;
import android.graphics.Bitmap;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheEntity;
import com.lzy.okgo.cache.CacheManager;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.callback.AbsCallback;
import com.lzy.okgo.callback.AbsCallbackWrapper;
import com.lzy.okgo.exception.OkGoException;
import com.lzy.okgo.model.HttpHeaders;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.BaseRequest;
import com.lzy.okgo.utils.HeaderParser;
import com.lzy.okgo.utils.HttpUtils;
import java.io.IOException;
import java.net.SocketTimeoutException;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.RequestBody;
/**
* ================================================
* 作 者:廖子尧
* 版 本:1.0
* 创建日期:2016/9/11
* 描 述:带缓存的请求
* 修订历史:
* ================================================
*/
public class CacheCall<T> implements Call<T> {
private volatile boolean canceled;
private boolean executed;
private BaseRequest baseRequest;
private okhttp3.Call rawCall;
private CacheEntity<T> cacheEntity;
private AbsCallback<T> mCallback;
private int currentRetryCount;
public CacheCall(BaseRequest baseRequest) {
this.baseRequest = baseRequest;
}
@Override
public void execute(AbsCallback<T> callback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
}
mCallback = callback;
if (mCallback == null) mCallback = new AbsCallbackWrapper<>();
//请求执行前UI线程调用
mCallback.onBefore(baseRequest);
//请求之前获取缓存信息,添加缓存头和其他的公共头
if (baseRequest.getCacheKey() == null)
baseRequest.setCacheKey(HttpUtils.createUrlFromParams(baseRequest.getBaseUrl(), baseRequest.getParams().urlParamsMap));
if (baseRequest.getCacheMode() == null) baseRequest.setCacheMode(CacheMode.NO_CACHE);
//无缓存模式,不需要进入缓存逻辑
final CacheMode cacheMode = baseRequest.getCacheMode();
if (cacheMode != CacheMode.NO_CACHE) {
//noinspection unchecked
cacheEntity = (CacheEntity<T>) CacheManager.INSTANCE.get(baseRequest.getCacheKey());
//检查缓存的有效时间,判断缓存是否已经过期
if (cacheEntity != null && cacheEntity.checkExpire(cacheMode, baseRequest.getCacheTime(), System.currentTimeMillis())) {
cacheEntity.setExpire(true);
}
HeaderParser.addCacheHeaders(baseRequest, cacheEntity, cacheMode);
}
//构建请求
RequestBody requestBody = baseRequest.generateRequestBody();
final Request request = baseRequest.generateRequest(baseRequest.wrapRequestBody(requestBody));
rawCall = baseRequest.generateCall(request);
if (cacheMode == CacheMode.IF_NONE_CACHE_REQUEST) {
//如果没有缓存,或者缓存过期,就请求网络,否者直接使用缓存
if (cacheEntity != null && !cacheEntity.isExpire()) {
T data = cacheEntity.getData();
HttpHeaders headers = cacheEntity.getResponseHeaders();
if (data == null || headers == null) {
//由于没有序列化等原因,可能导致数据为空
sendFailResultCallback(true, rawCall, null, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
} else {
sendSuccessResultCallback(true, data, rawCall, null);
return;//获取缓存成功,不请求网络
}
} else {
sendFailResultCallback(true, rawCall, null, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
}
} else if (cacheMode == CacheMode.FIRST_CACHE_THEN_REQUEST) {
//先使用缓存,不管是否存在,仍然请求网络
if (cacheEntity != null && !cacheEntity.isExpire()) {
T data = cacheEntity.getData();
HttpHeaders headers = cacheEntity.getResponseHeaders();
if (data == null || headers == null) {
//由于没有序列化等原因,可能导致数据为空
sendFailResultCallback(true, rawCall, null, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
} else {
sendSuccessResultCallback(true, data, rawCall, null);
}
} else {
sendFailResultCallback(true, rawCall, null, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
}
}
if (canceled) {
rawCall.cancel();
}
currentRetryCount = 0;
rawCall.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
if (e instanceof SocketTimeoutException && currentRetryCount < baseRequest.getRetryCount()) {
//超时重试处理
currentRetryCount++;
okhttp3.Call newCall = baseRequest.generateCall(call.request());
newCall.enqueue(this);
} else {
mCallback.parseError(call, e);
//请求失败,一般为url地址错误,网络错误等,并且过滤用户主动取消的网络请求
if (!call.isCanceled()) {
sendFailResultCallback(false, call, null, e);
}
}
}
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
int responseCode = response.code();
//304缓存数据
if (responseCode == 304 && cacheMode == CacheMode.DEFAULT) {
if (cacheEntity == null) {
sendFailResultCallback(true, call, response, OkGoException.INSTANCE("服务器响应码304,但是客户端没有缓存!"));
} else {
T data = cacheEntity.getData();
HttpHeaders headers = cacheEntity.getResponseHeaders();
if (data == null || headers == null) {
//由于没有序列化等原因,可能导致数据为空
sendFailResultCallback(true, call, response, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
} else {
sendSuccessResultCallback(true, data, call, response);
}
}
return;
}
//响应失败,一般为服务器内部错误,或者找不到页面等
if (responseCode == 404 || responseCode >= 500) {
sendFailResultCallback(false, call, response, OkGoException.INSTANCE("服务器数据异常!"));
return;
}
try {
Response<T> parseResponse = parseResponse(response);
T data = parseResponse.body();
//网络请求成功,保存缓存数据
handleCache(response.headers(), data);
//网络请求成功回调
sendSuccessResultCallback(false, data, call, response);
} catch (Exception e) {
//一般为服务器响应成功,但是数据解析错误
sendFailResultCallback(false, call, response, e);
}
}
});
}
/**
* 请求成功后根据缓存模式,更新缓存数据
*
* @param headers 响应头
* @param data 响应数据
*/
@SuppressWarnings("unchecked")
private void handleCache(Headers headers, T data) {
if (baseRequest.getCacheMode() == CacheMode.NO_CACHE) return; //不需要缓存,直接返回
if (data instanceof Bitmap) return; //Bitmap没有实现Serializable,不能缓存
CacheEntity<T> cache = HeaderParser.createCacheEntity(headers, data, baseRequest.getCacheMode(), baseRequest.getCacheKey());
if (cache == null) {
//服务器不需要缓存,移除本地缓存
CacheManager.INSTANCE.remove(baseRequest.getCacheKey());
} else {
//缓存命中,更新缓存
CacheManager.INSTANCE.replace(baseRequest.getCacheKey(), (CacheEntity<Object>) cache);
}
}
/** 失败回调,发送到主线程 */
@SuppressWarnings("unchecked")
private void sendFailResultCallback(final boolean isFromCache, final okhttp3.Call call, final okhttp3.Response response, final Exception e) {
final CacheMode cacheMode = baseRequest.getCacheMode();
OkGo.getInstance().getDelivery().post(new Runnable() {
@Override
public void run() {
if (isFromCache) {
mCallback.onCacheError(call, e); //缓存失败回调 (UI线程)
if (cacheMode == CacheMode.DEFAULT || cacheMode == CacheMode.REQUEST_FAILED_READ_CACHE) {
mCallback.onAfter(null, e); //请求结束回调 (UI线程)
}
} else {
mCallback.onError(call, response, e); //请求失败回调 (UI线程)
if (cacheMode != CacheMode.REQUEST_FAILED_READ_CACHE) {
mCallback.onAfter(null, e); //请求结束回调 (UI线程)
}
}
}
});
//不同的缓存模式,可能会导致该失败进入两次,一次缓存失败,一次网络请求失败
if (!isFromCache && cacheMode == CacheMode.REQUEST_FAILED_READ_CACHE) {
if (cacheEntity != null && !cacheEntity.isExpire()) {
T data = cacheEntity.getData();
HttpHeaders headers = cacheEntity.getResponseHeaders();
if (data == null || headers == null) {
//由于没有序列化等原因,可能导致数据为空
sendFailResultCallback(true, call, response, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
} else {
sendSuccessResultCallback(true, data, call, response);
}
} else {
sendFailResultCallback(true, call, response, OkGoException.INSTANCE("没有获取到缓存,或者缓存已经过期!"));
}
}
}
/** 成功回调,发送到主线程 */
private void sendSuccessResultCallback(final boolean isFromCache, final T t, final okhttp3.Call call, final okhttp3.Response response) {
final CacheMode cacheMode = baseRequest.getCacheMode();
OkGo.getInstance().getDelivery().post(new Runnable() {
@Override
public void run() {
if (isFromCache) {
mCallback.onCacheSuccess(t, call); //缓存成功回调 (UI线程)
if (cacheMode == CacheMode.DEFAULT || cacheMode == CacheMode.REQUEST_FAILED_READ_CACHE || cacheMode == CacheMode.IF_NONE_CACHE_REQUEST) {
mCallback.onAfter(t, null); //请求结束回调 (UI线程)
}
} else {
mCallback.onSuccess(t, call, response); //请求成功回调 (UI线程)
mCallback.onAfter(t, null); //请求结束回调 (UI线程)
}
}
});
}
@Override
public Response<T> execute() throws Exception {
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
}
okhttp3.Call call = baseRequest.getCall();
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
private Response<T> parseResponse(okhttp3.Response rawResponse) throws Exception {
//noinspection unchecked
T body = (T) baseRequest.getConverter().convertSuccess(rawResponse);
return Response.success(body, rawResponse);
}
@Override
public boolean isExecuted() {
return executed;
}
@Override
public void cancel() {
canceled = true;
if (rawCall != null) {
rawCall.cancel();
}
}
@Override
public boolean isCanceled() {
return canceled;
}
@Override
public Call<T> clone() {
return new CacheCall<>(baseRequest);
}
@Override
public BaseRequest getBaseRequest() {
return baseRequest;
}
}