fix(network): 修复重复请求拦截器去重失效问题
在请求发出前拦截重复请求,复用进行中请求的结果, 并在完成后保留 500ms 结果窗口;同时新增 DX11、G12NL 平台标识与构建变体,更新版本号至 1.6.0914。
This commit is contained in:
69
build.gradle
69
build.gradle
@@ -75,8 +75,8 @@ android {
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 28
|
||||
|
||||
versionCode 206
|
||||
versionName "1.6.0731"
|
||||
versionCode 209
|
||||
versionName "1.6.0914"
|
||||
|
||||
ndk {
|
||||
//选择要添加的对应 cpu 类型的 .so 库。
|
||||
@@ -256,13 +256,36 @@ android {
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
|
||||
MT6789 {
|
||||
storeFile file("keystore/MT6789.keystore")
|
||||
storePassword "123456"
|
||||
keyAlias "mt6789"
|
||||
keyPassword "123456"
|
||||
v1SigningEnabled true
|
||||
v2SigningEnabled true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
G12NLDebug.initWith(debug)
|
||||
G12NLDebug {
|
||||
buildConfigField "String", "platform", '"G12NL"'
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.MT6789
|
||||
}
|
||||
|
||||
G12NLRelease.initWith(release)
|
||||
G12NLRelease {
|
||||
buildConfigField "String", "platform", '"G12NL"'
|
||||
signingConfig signingConfigs.MT6789
|
||||
}
|
||||
|
||||
DX11Debug.initWith(debug)
|
||||
DX11Debug {
|
||||
buildConfigField "String", "platform", '"DX11"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.DX11
|
||||
}
|
||||
@@ -276,7 +299,7 @@ android {
|
||||
G122Debug.initWith(debug)
|
||||
G122Debug {
|
||||
buildConfigField "String", "platform", '"MT6765"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G122
|
||||
}
|
||||
@@ -290,7 +313,7 @@ android {
|
||||
QualcommDebug.initWith(debug)
|
||||
QualcommDebug {
|
||||
buildConfigField "String", "platform", '"QualcommA"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.zhanRui
|
||||
}
|
||||
@@ -304,7 +327,7 @@ android {
|
||||
G128TDebug.initWith(debug)
|
||||
G128TDebug {
|
||||
buildConfigField "String", "platform", '"G128T"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G128T
|
||||
}
|
||||
@@ -318,7 +341,7 @@ android {
|
||||
QZ15Debug.initWith(debug)
|
||||
QZ15Debug {
|
||||
buildConfigField "String", "platform", '"QZA15"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.U1302
|
||||
}
|
||||
@@ -331,7 +354,7 @@ android {
|
||||
|
||||
seewoDebug.initWith(debug)
|
||||
seewoDebug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.seewo
|
||||
buildConfigField "String", "platform", '"seewo"'
|
||||
@@ -345,7 +368,7 @@ android {
|
||||
|
||||
P50Debug.initWith(debug)
|
||||
P50Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.P50
|
||||
buildConfigField "String", "platform", '"P50TD"'
|
||||
@@ -359,7 +382,7 @@ android {
|
||||
|
||||
T40AirDebug.initWith(debug)
|
||||
T40AirDebug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.T40Air
|
||||
buildConfigField "String", "platform", '"HL500"'
|
||||
@@ -373,7 +396,7 @@ android {
|
||||
|
||||
// AiUduDebug.initWith(debug)
|
||||
// AiUduDebug {
|
||||
// versionNameSuffix "-debug"
|
||||
// versionNameSuffix "_debug"
|
||||
// debuggable true
|
||||
// signingConfig signingConfigs.G10P
|
||||
// buildConfigField "String", "platform", '"AUDG104"'
|
||||
@@ -387,7 +410,7 @@ android {
|
||||
|
||||
Huaruian8768Debug.initWith(debug)
|
||||
Huaruian8768Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.Huaruian8768
|
||||
buildConfigField "String", "platform", '"MT8768"'
|
||||
@@ -401,7 +424,7 @@ android {
|
||||
|
||||
G11Debug.initWith(debug)
|
||||
G11Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G11Userdebug
|
||||
buildConfigField "String", "platform", '"MTKG11"'
|
||||
@@ -415,7 +438,7 @@ android {
|
||||
|
||||
YXPD1Debug.initWith(debug)
|
||||
YXPD1Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G10P
|
||||
buildConfigField "String", "platform", '"YXPD1"'
|
||||
@@ -429,7 +452,7 @@ android {
|
||||
|
||||
c2Debug.initWith(debug)
|
||||
c2Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.teclast8183
|
||||
buildConfigField "String", "platform", '"MTK8183"'
|
||||
@@ -443,7 +466,7 @@ android {
|
||||
|
||||
G10PDebug.initWith(debug)
|
||||
G10PDebug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G10P
|
||||
buildConfigField "String", "platform", '"G10P"'
|
||||
@@ -458,7 +481,7 @@ android {
|
||||
G104Debug.initWith(debug)
|
||||
G104Debug {
|
||||
buildConfigField "String", "platform", '"MTK11"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.G10P
|
||||
}
|
||||
@@ -471,7 +494,7 @@ android {
|
||||
|
||||
zhanRuiDebug.initWith(debug)
|
||||
zhanRuiDebug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
buildConfigField "String", "platform", '"ZhanRui"'
|
||||
debuggable true
|
||||
signingConfig signingConfigs.zhanRui
|
||||
@@ -486,7 +509,7 @@ android {
|
||||
//userdebug rom使用这个版本
|
||||
zhanRuiUserdebug.initWith(zhanRuiDebug)
|
||||
zhanRuiUserdebug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
buildConfigField "String", "platform", '"ZhanRui"'
|
||||
debuggable true
|
||||
signingConfig signingConfigs.zhanRuiUserdebug
|
||||
@@ -494,7 +517,7 @@ android {
|
||||
|
||||
zhanRui12Debug.initWith(debug)
|
||||
zhanRui12Debug {
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
buildConfigField "String", "platform", '"AH6016"'
|
||||
debuggable true
|
||||
signingConfig signingConfigs.zhanRui12
|
||||
@@ -509,7 +532,7 @@ android {
|
||||
TeclastP20SDebug.initWith(debug)
|
||||
TeclastP20SDebug {
|
||||
debuggable true
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
buildConfigField "String", "platform", '"P20S"'
|
||||
signingConfig signingConfigs.TeclastP20S
|
||||
}
|
||||
@@ -523,7 +546,7 @@ android {
|
||||
zhanruiG10ZDebug.initWith(debug)
|
||||
zhanruiG10ZDebug {
|
||||
buildConfigField "String", "platform", '"ZR6016"'
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
debuggable true
|
||||
signingConfig signingConfigs.zhanruiG10Z
|
||||
}
|
||||
@@ -537,7 +560,7 @@ android {
|
||||
debug {
|
||||
buildConfigField "String", "platform", '"MTK"'
|
||||
debuggable true
|
||||
versionNameSuffix "-debug"
|
||||
versionNameSuffix "_debug"
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.mtk
|
||||
|
||||
@@ -15,6 +15,10 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
MX11Debug {}
|
||||
MX11Release {}
|
||||
G12NLDebug {}
|
||||
G12NLRelease {}
|
||||
DX11Debug {}
|
||||
DX11Release {}
|
||||
G122Debug {}
|
||||
|
||||
BIN
keystore/MT6789.keystore
Normal file
BIN
keystore/MT6789.keystore
Normal file
Binary file not shown.
@@ -208,6 +208,10 @@ public class NetInterfaceManager {
|
||||
set.add(JgyUtils.AUDG104Tag);
|
||||
} else if (platform == JgyUtils.seewoPlatform) {
|
||||
set.add(JgyUtils.seewoTag);
|
||||
} else if (platform == JgyUtils.DX11Platform) {
|
||||
set.add(JgyUtils.DX11_TAG);
|
||||
} else if (platform == JgyUtils.G12NLPlatform) {
|
||||
set.add(JgyUtils.G12NL_TAG);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,9 +8,13 @@ import com.aoleyun.os.uiuiutils.MD5Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Protocol;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
@@ -19,89 +23,292 @@ import okhttp3.ResponseBody;
|
||||
import okio.Buffer;
|
||||
|
||||
/**
|
||||
* v1.0 2022-07-15 16:16:52
|
||||
* 重复请求拦截器。
|
||||
*
|
||||
* <p>原实现是在 {@code chain.proceed()} 之后才判断是否为重复请求,此时请求早已发到服务器,
|
||||
* 只能丢弃返回结果,所以服务端依然会收到两次(甚至多次)请求;并且记录在 finally 中立即删除,
|
||||
* 去重窗口几乎为零,重复请求根本拦不住。</p>
|
||||
*
|
||||
* <p>优化后的策略:</p>
|
||||
* <ul>
|
||||
* <li>发请求之前先判断是否已经有相同请求:有则等待它的结果并复用,不再访问服务器;</li>
|
||||
* <li>请求完成后在 {@link #REUSE_WINDOW_MS} 内保留结果,短时间内相同的请求直接复用结果;</li>
|
||||
* <li>复用时使用真实的状态码、响应头和响应体,调用方无感知(原来的空 {@link Response} 会让
|
||||
* 解析层直接抛异常);</li>
|
||||
* <li>无响应体或响应体过大(超过 {@link #MAX_DEDUP_BODY_BYTES})的请求不参与去重,直接透传,
|
||||
* 避免占用大量内存。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>v1.0 2022-07-15 16:16:52</p>
|
||||
*/
|
||||
public class RepeatRequestInterceptor implements Interceptor {
|
||||
private static final String TAG = RepeatRequestInterceptor.class.getSimpleName();
|
||||
private static final String TAG = "RepeatRequestInterceptor";
|
||||
|
||||
private final ConcurrentHashMap<String, Long> requestIdsMap = new ConcurrentHashMap<>();
|
||||
public static final String REPEAT_REQUEST_PROTOCOL = "OKHTTP_REPEAT_REQUEST_PROTOCOL";
|
||||
/**
|
||||
* 等待进行中请求返回结果的最长时间,超时后本次请求自己访问服务器。
|
||||
* 需要大于 OkHttpClient 的超时时间(当前为 5 秒)。
|
||||
*/
|
||||
private static final long WAIT_IN_FLIGHT_TIMEOUT_MS = 10_000L;
|
||||
|
||||
/**
|
||||
* 请求完成后结果保留的时间。在该时间内收到相同请求,直接复用结果,不再访问服务器。
|
||||
* 需要小于业务侧的刷新间隔(ConnectMode 最小为 1 分钟)。
|
||||
*/
|
||||
private static final long REUSE_WINDOW_MS = 500L;
|
||||
|
||||
/** 超过该大小的响应体不参与去重(直接透传),避免内存占用 */
|
||||
private static final long MAX_DEDUP_BODY_BYTES = 1024 * 1024L;
|
||||
|
||||
/** 参与去重 key 计算的请求体最大字节数 */
|
||||
private static final int MAX_BODY_BYTES_FOR_KEY = 8 * 1024;
|
||||
|
||||
/** 日志中请求体、响应体的最大长度 */
|
||||
private static final int MAX_LOG_BODY_LENGTH = 10240;
|
||||
|
||||
private final ConcurrentHashMap<String, RepeatRecord> recordMap = new ConcurrentHashMap<>();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Response intercept(@NotNull Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
Response response = chain.proceed(request);
|
||||
ResponseBody responseBody = response.body();
|
||||
String bodyText = requestBodyToString(request.body());
|
||||
String requestKey = buildRequestKey(request, bodyText);
|
||||
|
||||
//会消费请求,导致请求多次
|
||||
String content = responseBody.string();
|
||||
// Response copy = response.newBuilder().body(responseBody).build();
|
||||
ResponseBody copy = ResponseBody.create(responseBody.contentType(), content);
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(TAG, "请求体返回:| Response: " + request.url().encodedPath() + "\t body: " + content);
|
||||
clearExpiredRecords();
|
||||
|
||||
RepeatRecord record = acquireRecord(requestKey);
|
||||
if (record == null) {
|
||||
// 已有相同请求,但没有拿到可用结果(上一次失败、超时或结果过大),本次请求直接访问服务器
|
||||
return chain.proceed(request);
|
||||
}
|
||||
//相同的请求
|
||||
String requestKey = MD5Util.getUpperMD5Str(request.method() + request.url().toString() + requestBodyToString(request.body()));
|
||||
long time = System.currentTimeMillis();//请求时间
|
||||
if (!record.isOwner()) {
|
||||
// 复用相同请求的结果:服务端只会收到一次请求
|
||||
log("复用请求:", requestKey, request, bodyText);
|
||||
return record.newResponse(request);
|
||||
}
|
||||
|
||||
log("注册请求:", requestKey, request, bodyText);
|
||||
try {
|
||||
if (requestIdsMap.size() > 0 && requestIdsMap.containsKey(requestKey)) {
|
||||
log("重复请求:", requestKey, request);
|
||||
//下面这行写了不会抛出onerror
|
||||
// chain.call().cancel();
|
||||
return new Response.Builder()
|
||||
.protocol(Protocol.get(REPEAT_REQUEST_PROTOCOL))
|
||||
.request(request) //multi thread
|
||||
.build();
|
||||
Response response = chain.proceed(request);
|
||||
ResponseBody responseBody = response.body();
|
||||
if (responseBody == null || responseBody.contentLength() > MAX_DEDUP_BODY_BYTES) {
|
||||
// 无响应体或响应体过大:不消费 body,也不参与去重,直接透传
|
||||
logResponse(request, null);
|
||||
return response;
|
||||
}
|
||||
requestIdsMap.put(requestKey, time);
|
||||
log("注册请求:", requestKey, request);
|
||||
// RepeatRequestInterceptor.Builder builder = request.newBuilder();
|
||||
// builder.addHeader("header", jsonObject.toString());
|
||||
return response.newBuilder().body(copy).build();
|
||||
|
||||
// body 只能被消费一次,读出来之后重建一个新的 body 返回给调用方
|
||||
MediaType contentType = responseBody.contentType();
|
||||
byte[] bytes = responseBody.bytes();
|
||||
logResponse(request, bytes);
|
||||
if (bytes.length <= MAX_DEDUP_BODY_BYTES) {
|
||||
// 缓存结果,供等待中的、以及短时间内后续的相同请求复用
|
||||
record.complete(response, bytes, contentType);
|
||||
}
|
||||
return response.newBuilder().body(ResponseBody.create(contentType, bytes)).build();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "intercept: " + e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
if (requestIdsMap.containsKey(requestKey) && requestIdsMap.containsValue(time)) {//请求任务完成删除map中的数据
|
||||
requestIdsMap.remove(requestKey);
|
||||
log("移除请求:", requestKey, request);
|
||||
// 兜底:无论成功、失败还是异常,都结束记录,避免等待中的相同请求被一直阻塞
|
||||
record.finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求对应的去重记录。
|
||||
*
|
||||
* @return 返回记录表示本次请求要么成为 owner 去访问服务器、要么直接复用已有结果;
|
||||
* 返回 null 表示已有相同请求但结果不可用,本次请求自己访问服务器(不参与去重)
|
||||
*/
|
||||
private RepeatRecord acquireRecord(String requestKey) {
|
||||
while (true) {
|
||||
long now = System.currentTimeMillis();
|
||||
RepeatRecord record = recordMap.get(requestKey);
|
||||
if (record == null) {
|
||||
RepeatRecord created = new RepeatRecord();
|
||||
if (recordMap.putIfAbsent(requestKey, created) == null) {
|
||||
created.markOwner();
|
||||
return created;
|
||||
}
|
||||
continue;// 其他线程抢先注册,重新判断
|
||||
}
|
||||
if (record.isExpired(now)) {
|
||||
// 结果已过期,替换为本次请求的记录并成为 owner
|
||||
RepeatRecord created = new RepeatRecord();
|
||||
if (recordMap.replace(requestKey, record, created)) {
|
||||
created.markOwner();
|
||||
return created;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 已有相同请求:等待它的结果,拿到结果直接复用
|
||||
if (record.await(WAIT_IN_FLIGHT_TIMEOUT_MS)) {
|
||||
return record;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** 清理过期记录,释放其缓存的响应体 */
|
||||
private void clearExpiredRecords() {
|
||||
if (recordMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
for (Map.Entry<String, RepeatRecord> entry : recordMap.entrySet()) {
|
||||
RepeatRecord record = entry.getValue();
|
||||
if (record.isExpired(now)) {
|
||||
recordMap.remove(entry.getKey(), record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String action, String requestKey, Request request) {
|
||||
private static String buildRequestKey(Request request, String bodyText) {
|
||||
return MD5Util.getUpperMD5Str(request.method() + "|" + request.url() + "|" + bodyText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求体转字符串,用于计算去重 key 和输出日志。
|
||||
* 只读取可重复读写的请求体,避免把一次性(one-shot)请求体读空。
|
||||
*/
|
||||
private static String requestBodyToString(RequestBody body) {
|
||||
if (body == null || body.isOneShot()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
Buffer buffer = new Buffer();
|
||||
body.writeTo(buffer);
|
||||
long size = buffer.size();
|
||||
if (size > MAX_BODY_BYTES_FOR_KEY) {
|
||||
// 请求体过大时只取前一部分参与去重,避免不必要的内存开销
|
||||
return size + ":" + buffer.readByteString(MAX_BODY_BYTES_FOR_KEY).hex();
|
||||
}
|
||||
return buffer.readUtf8();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(String action, String requestKey, Request request, String bodyText) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e("REPEAT-REQUEST", action + requestKey + " Method @" + request.method() + " --- " + " URL = " + request.url().encodedPath() + "\t" + bodyToString(request));
|
||||
String body = bodyText.length() > MAX_LOG_BODY_LENGTH ? "-too long" : bodyText;
|
||||
Log.e("REPEAT-REQUEST", action + requestKey + " Method @" + request.method()
|
||||
+ " --- " + " URL = " + request.url().encodedPath() + "\t" + body);
|
||||
} else {
|
||||
Log.e("REPEAT-REQUEST", action + requestKey + " Method @" + request.method());
|
||||
}
|
||||
}
|
||||
|
||||
private static String bodyToString(final Request request) {
|
||||
try {
|
||||
final Request copy = request.newBuilder().build();
|
||||
final Buffer buffer = new Buffer();
|
||||
copy.body().writeTo(buffer);
|
||||
if (buffer.size() > 4096) {
|
||||
return "-too long";
|
||||
}
|
||||
return buffer.readUtf8();
|
||||
} catch (Exception e) {
|
||||
return "-";
|
||||
private static void logResponse(Request request, byte[] bytes) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
return;
|
||||
}
|
||||
if (bytes == null || bytes.length > MAX_LOG_BODY_LENGTH) {
|
||||
Log.e(TAG, "请求体返回:| Response: " + request.url() + "\t body: too long");
|
||||
} else {
|
||||
Log.e(TAG, "请求体返回:| Response: " + request.url()
|
||||
+ "\t body: " + new String(bytes, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
private static String requestBodyToString(RequestBody body) {
|
||||
try {
|
||||
final Buffer buffer = new Buffer();
|
||||
body.writeTo(buffer);
|
||||
if (buffer.size() > 4096) {
|
||||
return "-too long";
|
||||
/**
|
||||
* 一次请求的去重记录:owner 线程负责访问服务器,其他相同请求等待并复用它的结果
|
||||
*/
|
||||
private static final class RepeatRecord {
|
||||
private final Object lock = new Object();
|
||||
private final long createdTime = System.currentTimeMillis();
|
||||
|
||||
private boolean owner;
|
||||
private boolean finished;
|
||||
private boolean succeed;
|
||||
private long finishedTime;
|
||||
private byte[] body;
|
||||
private MediaType contentType;
|
||||
private Headers headers;
|
||||
private Protocol protocol;
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
void markOwner() {
|
||||
owner = true;
|
||||
}
|
||||
|
||||
boolean isOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待 owner 请求结束
|
||||
*
|
||||
* @return true 表示已拿到可复用的结果
|
||||
*/
|
||||
boolean await(long timeoutMs) {
|
||||
synchronized (lock) {
|
||||
if (!finished) {
|
||||
try {
|
||||
lock.wait(timeoutMs);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
return finished && succeed;
|
||||
}
|
||||
}
|
||||
|
||||
/** 请求成功,缓存结果并唤醒等待的请求 */
|
||||
void complete(Response response, byte[] body, MediaType contentType) {
|
||||
synchronized (lock) {
|
||||
if (finished) {
|
||||
return;
|
||||
}
|
||||
this.body = body;
|
||||
this.contentType = contentType;
|
||||
this.headers = response.headers();
|
||||
this.protocol = response.protocol();
|
||||
this.code = response.code();
|
||||
this.message = response.message();
|
||||
this.succeed = true;
|
||||
finished = true;
|
||||
finishedTime = System.currentTimeMillis();
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/** 请求结束(失败或异常时没有可复用的结果);重复调用忽略 */
|
||||
void finish() {
|
||||
synchronized (lock) {
|
||||
if (finished) {
|
||||
return;
|
||||
}
|
||||
finished = true;
|
||||
finishedTime = System.currentTimeMillis();
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/** 进行中的记录超过等待超时时间、已完成的记录超过结果保留时间即视为过期 */
|
||||
boolean isExpired(long now) {
|
||||
synchronized (lock) {
|
||||
if (!finished) {
|
||||
return now - createdTime > WAIT_IN_FLIGHT_TIMEOUT_MS;
|
||||
}
|
||||
return now - finishedTime > REUSE_WINDOW_MS;
|
||||
}
|
||||
}
|
||||
|
||||
/** 用缓存的结果构建响应,状态码、响应头、响应体都是真实数据 */
|
||||
Response newResponse(Request request) {
|
||||
synchronized (lock) {
|
||||
return new Response.Builder()
|
||||
.request(request)
|
||||
.protocol(protocol)
|
||||
.code(code)
|
||||
.message(message)
|
||||
.headers(headers)
|
||||
.body(ResponseBody.create(contentType, body))
|
||||
.build();
|
||||
}
|
||||
return buffer.readUtf8();
|
||||
} catch (Exception e) {
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ public class JgyUtils {
|
||||
public static final int MT8768Platform = 17;
|
||||
public static final int AUDG104Platform = 18;
|
||||
public static final int seewoPlatform = 25;
|
||||
public static final int DX11Platform = 31;
|
||||
public static final int G12NLPlatform = 32;
|
||||
|
||||
|
||||
public static final String Other = "其他";
|
||||
public static final String MTKTag = "MTK";
|
||||
@@ -62,6 +65,8 @@ public class JgyUtils {
|
||||
public static final String MT8768Tag = "MT8768";
|
||||
public static final String AUDG104Tag = "AUDG104";
|
||||
public static final String seewoTag = "seewo";
|
||||
public static final String DX11_TAG = "DX11";
|
||||
public static final String G12NL_TAG = "G12NL";
|
||||
|
||||
|
||||
private JgyUtils(Context context) {
|
||||
@@ -120,6 +125,12 @@ public class JgyUtils {
|
||||
} else if (seewoTag.equalsIgnoreCase(platform)) {
|
||||
Log.i(TAG, "checkAppPlatform: " + "seewo");
|
||||
return seewoPlatform;
|
||||
} else if (DX11_TAG.equalsIgnoreCase(platform)) {
|
||||
Log.i(TAG, "checkAppPlatform: " + "DX11");
|
||||
return DX11Platform;
|
||||
} else if (G12NL_TAG.equalsIgnoreCase(platform)) {
|
||||
Log.i(TAG, "checkAppPlatform: " + "G12NL");
|
||||
return G12NLPlatform;
|
||||
} else {
|
||||
Log.i(TAG, "checkAppPlatform: " + "没有数据");
|
||||
return UnknowPlatform;
|
||||
@@ -154,6 +165,10 @@ public class JgyUtils {
|
||||
getAppPlatformCallback.AppPlatform(AUDG104Platform);
|
||||
} else if (seewoTag.equalsIgnoreCase(platform)) {
|
||||
getAppPlatformCallback.AppPlatform(seewoPlatform);
|
||||
} else if (DX11_TAG.equalsIgnoreCase(platform)) {
|
||||
getAppPlatformCallback.AppPlatform(DX11Platform);
|
||||
} else if (G12NL_TAG.equalsIgnoreCase(platform)) {
|
||||
getAppPlatformCallback.AppPlatform(G12NLPlatform);
|
||||
} else {
|
||||
getAppPlatformCallback.AppPlatform(UnknowPlatform);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user