關(guān)鍵點
- 判斷請求是否相同: request轉(zhuǎn)key,根據(jù)key判斷
- 請求進行中: 等待
- 請求已完成: 返回緩存的response
- 過去這段時間后,清除緩存的response
代碼實現(xiàn):
public class SameRequestFilterInterceptor implements Interceptor {
static WeakHashMap<String, ResonseForClone> responseWeakHashMap = new WeakHashMap<>();
static WeakHashMap<String, WeakReference<Call>> calls = new WeakHashMap<>();
static Charset UTF_8 = Charset.forName("UTF-8");
static IConfig config;
static boolean enableFilter;
static boolean debug;
static Handler handler;
/**
* @param enableFilter 全局開關(guān)
* @param config 配置信息
*/
public static void config(boolean debug, boolean enableFilter, IConfig config) {
SameRequestFilterInterceptor.enableFilter = enableFilter;
SameRequestFilterInterceptor.config = config;
SameRequestFilterInterceptor.debug = debug;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!enableFilter) {
return chain.proceed(request);
}
if (config == null) {
return chain.proceed(request);
}
if (!config.shouldFilter(request.url().toString())) {
return chain.proceed(request);
}
String key = generateKey(request);
return check(chain, request, key);
}
private Response check(Chain chain, Request request, String key) throws IOException {
try {
//從緩存的call和response中判斷要不要等待
boolean needwait = needwait(key);
if (!needwait) {
if (responseWeakHashMap.containsKey(key)) {
return responseWeakHashMap.get(key).getClonedResonse();
} else {
//直接執(zhí)行請求:
//將response緩存起來
return realExceute(chain, request, key);
}
} else {
Thread.sleep(2000);
return check(chain, request, key);
}
} catch (InterruptedException e) {
e.printStackTrace();
if (responseWeakHashMap.containsKey(key)) {
return responseWeakHashMap.get(key).getClonedResonse();
} else {
//直接執(zhí)行請求:
//將response緩存起來
return realExceute(chain, request, key);
}
}
}
@NonNull
private Response realExceute(Chain chain, Request request, String key) throws IOException {
calls.put(key, new WeakReference<>(chain.call()));
Response response = chain.proceed(request);
if (response.isSuccessful() && response.body() != null) {
ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(responseBody.contentLength() > 0 ? responseBody.contentLength() : Integer.MAX_VALUE);
//嚇人?
Buffer buffer = source.buffer();
Charset charset = UTF_8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF_8);
}
String bodyString = buffer.clone().readString(charset);
ResponseBody cloneBody = ResponseBody.create(response.body().contentType(), bodyString);
Response responseClone = new Response.Builder()
.code(response.code())
.protocol(response.protocol())
.message(response.message())
.body(cloneBody)
.headers(response.headers())
.header("cachedResonse", "yes")
.request(request)
.build();
responseWeakHashMap.put(key, new ResonseForClone(bodyString, responseClone));
calls.remove(key);
getMainHandler().postDelayed(new Runnable() {
@Override
public void run() {
//1min后移除緩存的response:
responseWeakHashMap.remove(key);
logw(config.responseCacheTimeInMills() + "時間到了,清除緩存的response");
}
}, config.responseCacheTimeInMills());
}
return response;
}
private static Handler getMainHandler() {
if (handler == null) {
handler = new Handler(Looper.getMainLooper());
}
return handler;
}
private boolean needwait(String key) {
if (responseWeakHashMap.containsKey(key)) {
logw("有緩存的response,直接去讀緩存,并組裝新的response");
return false;
}
if (calls.containsKey(key)) {
WeakReference<Call> callWeakReference = calls.get(key);
if (callWeakReference == null) {
logw("不需要等待,直接發(fā)請求 call WeakReference not exist:");
return false;
}
Call call = callWeakReference.get();
if (call == null || call.isCanceled()) {
logw("不需要等待,直接發(fā)請求 call not exist or is canceld:" + call);
return false;
}
logw("請求可能正在等待或正在執(zhí)行-needwait call is running:" + call);
//請求可能正在等待或正在執(zhí)行
return true;
}
logw("任何地方都沒有,不需要等,直接執(zhí)行請求");
//任何地方都沒有,不需要等,直接執(zhí)行請求
return false;
}
private static void logw(String str) {
if (debug) {
Log.w("requestFilter", str);
}
}
/**
* @param request
* @return
*/
private String generateKey(Request request) {
return config.generateCacheKey(request);
}
class ResonseForClone {
String body;
Response response;
public ResonseForClone(String body, Response response) {
this.body = body;
this.response = response;
}
public Response getClonedResonse() {
ResponseBody cloneBody = ResponseBody.create(response.body().contentType(), body);
Response responseClone = new Response.Builder()
.code(response.code())
.protocol(response.protocol())
.message(response.message())
.body(cloneBody)
.headers(response.headers())
.header("cachedResonse", "yes")
.request(response.request())
.build();
return responseClone;
}
}
public interface IConfig {
boolean shouldFilter(String url);
String generateCacheKey(Request request);
long responseCacheTimeInMills();
}
}
使用:
SameRequestFilterInterceptor.config(Config.enableLog(), true, new SameRequestFilterInterceptor.IConfig() {
@Override
public boolean shouldFilter(String url) {
return true;
}
@Override
public String generateCacheKey(Request request) {
return request.url().toString();
}
@Override
public long responseCacheTimeInMills() {
return 60000;
}
});
commonInterceptors.add(new SameRequestFilterInterceptor());
demo:
for (int i = 0; i < 20; i++) {
request();
}
日志: