mirror of
https://github.com/WuKongIM/WuKongIMAndroidSDK
synced 2025-05-29 12:42:29 +00:00
fix:优化连接
This commit is contained in:
parent
61dd373418
commit
16c6ca8d57
@ -3,3 +3,42 @@ description:
|
|||||||
globs:
|
globs:
|
||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
# 连接管理机制
|
||||||
|
|
||||||
|
## 连接状态流转
|
||||||
|
连接状态在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中管理,遵循以下规则:
|
||||||
|
|
||||||
|
### 有效的状态转换
|
||||||
|
- 失败状态 -> 连接中/成功
|
||||||
|
- 连接中 -> 成功/失败/无网络
|
||||||
|
- 成功 -> 同步消息/被踢/失败
|
||||||
|
- 同步消息 -> 成功/失败
|
||||||
|
- 无网络 -> 连接中/失败
|
||||||
|
|
||||||
|
### 关键同步点
|
||||||
|
所有状态转换都需要通过 `connectionLock` 同步锁保护:
|
||||||
|
```java
|
||||||
|
synchronized (connectionLock) {
|
||||||
|
// 状态转换操作
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 重连机制
|
||||||
|
重连策略采用指数退避算法:
|
||||||
|
- 基础延迟:1秒
|
||||||
|
- 最大延迟:32秒
|
||||||
|
- 最大重试次数:5次
|
||||||
|
|
||||||
|
## 连接关闭处理
|
||||||
|
连接关闭流程:
|
||||||
|
1. 使用 `isClosing` 原子变量防止重复关闭
|
||||||
|
2. 设置连接标记防止重连
|
||||||
|
3. 清理连接资源
|
||||||
|
4. 触发超时强制关闭
|
||||||
|
|
||||||
|
## 异常处理
|
||||||
|
主要在 [ConnectionClient.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/ConnectionClient.java) 中处理:
|
||||||
|
- 连接异常
|
||||||
|
- 连接超时
|
||||||
|
- 心跳超时
|
||||||
|
- 空闲超时
|
||||||
|
@ -3,3 +3,36 @@ description:
|
|||||||
globs:
|
globs:
|
||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
# 消息处理机制
|
||||||
|
|
||||||
|
## 消息发送流程
|
||||||
|
在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中实现:
|
||||||
|
|
||||||
|
### 发送前检查
|
||||||
|
- 检查连接状态
|
||||||
|
- 验证消息完整性
|
||||||
|
- 处理附件(图片、视频等)
|
||||||
|
|
||||||
|
### 消息队列管理
|
||||||
|
使用 `sendingMsgHashMap` 管理发送中的消息:
|
||||||
|
- 消息重发机制
|
||||||
|
- 发送超时处理
|
||||||
|
- 发送状态追踪
|
||||||
|
|
||||||
|
### 消息同步
|
||||||
|
两种同步模式:
|
||||||
|
- WRITE模式:完整消息同步
|
||||||
|
- READ模式:仅同步会话列表
|
||||||
|
|
||||||
|
## 消息接收处理
|
||||||
|
主要在 ConnectionClient 的 onData 方法中处理:
|
||||||
|
- 消息解析
|
||||||
|
- 重复消息过滤
|
||||||
|
- 消息排序
|
||||||
|
- 存储和回调
|
||||||
|
|
||||||
|
## 特殊消息处理
|
||||||
|
- 心跳消息(ping/pong)
|
||||||
|
- 连接确认消息
|
||||||
|
- 踢下线消息
|
||||||
|
- 同步完成消息
|
||||||
|
@ -3,3 +3,38 @@ description:
|
|||||||
globs:
|
globs:
|
||||||
alwaysApply: false
|
alwaysApply: false
|
||||||
---
|
---
|
||||||
|
# WuKongIM Android SDK 项目结构
|
||||||
|
|
||||||
|
WuKongIM Android SDK 是一个即时通讯SDK,主要包含以下核心组件:
|
||||||
|
|
||||||
|
## 核心连接管理
|
||||||
|
主要连接管理类在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中实现,负责:
|
||||||
|
- Socket连接的建立和维护
|
||||||
|
- 消息的发送和接收
|
||||||
|
- 重连机制
|
||||||
|
- 心跳管理
|
||||||
|
|
||||||
|
## 连接状态处理
|
||||||
|
连接状态定义在 [WKConnectStatus.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/type/WKConnectStatus.java) 中,包括:
|
||||||
|
- 连接成功(1)
|
||||||
|
- 连接失败(0)
|
||||||
|
- 被踢下线(2)
|
||||||
|
- 同步消息中(3)
|
||||||
|
- 连接中(4)
|
||||||
|
- 无网络(5)
|
||||||
|
- 同步完成(6)
|
||||||
|
|
||||||
|
## 客户端连接处理
|
||||||
|
[ConnectionClient.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/ConnectionClient.java) 处理具体的连接事件:
|
||||||
|
- 连接建立回调
|
||||||
|
- 数据接收
|
||||||
|
- 连接断开处理
|
||||||
|
- 超时处理
|
||||||
|
- 异常处理
|
||||||
|
|
||||||
|
## 应用配置
|
||||||
|
[WKIMApplication.java](mdc:wkim/src/main/java/com/xinbida/wukongim/WKIMApplication.java) 管理SDK全局配置:
|
||||||
|
- 协议版本
|
||||||
|
- 同步消息模式
|
||||||
|
- 网络状态
|
||||||
|
- 数据库配置
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,5 +13,4 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
/repository
|
|
||||||
.cursor
|
.cursor
|
||||||
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
2a8fa0fa06d069610eed09005b343994
|
@ -0,0 +1 @@
|
|||||||
|
34a3a10b015c40e16a76fe75cb974d675a9cbda6
|
@ -0,0 +1 @@
|
|||||||
|
eb0a4ee07731a3ef38f606b2978d16169a6f6388e3f33fa3a10c82f3b0c17bb0
|
@ -0,0 +1 @@
|
|||||||
|
d1a0aa32976653fa04696f6d42edbe8152b59fdaf0135350cdefa14d571212571e85412c8f026a46e43069aadad3603358b63e262635a3716c948dab7b056750
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
195544eb25003c80879e6390c389f4b5
|
@ -0,0 +1 @@
|
|||||||
|
d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8
|
@ -0,0 +1 @@
|
|||||||
|
2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28
|
@ -0,0 +1 @@
|
|||||||
|
67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d
|
@ -0,0 +1,140 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": "1.1",
|
||||||
|
"component": {
|
||||||
|
"group": "com.xinbida.wukongim",
|
||||||
|
"module": "WKIMLib_local",
|
||||||
|
"version": "1.0.7",
|
||||||
|
"attributes": {
|
||||||
|
"org.gradle.status": "release"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"createdBy": {
|
||||||
|
"gradle": {
|
||||||
|
"version": "8.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"variants": [
|
||||||
|
{
|
||||||
|
"name": "releaseApiElements-published",
|
||||||
|
"attributes": {
|
||||||
|
"org.gradle.category": "library",
|
||||||
|
"org.gradle.usage": "java-api",
|
||||||
|
"org.jetbrains.kotlin.platform.type": "androidJvm"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"name": "WKIMLib_local-1.0.7.aar",
|
||||||
|
"url": "WKIMLib_local-1.0.7.aar",
|
||||||
|
"size": 619369,
|
||||||
|
"sha512": "67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d",
|
||||||
|
"sha256": "2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28",
|
||||||
|
"sha1": "d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8",
|
||||||
|
"md5": "195544eb25003c80879e6390c389f4b5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "releaseRuntimeElements-published",
|
||||||
|
"attributes": {
|
||||||
|
"org.gradle.category": "library",
|
||||||
|
"org.gradle.usage": "java-runtime",
|
||||||
|
"org.jetbrains.kotlin.platform.type": "androidJvm"
|
||||||
|
},
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"group": "org.jetbrains.kotlin",
|
||||||
|
"module": "kotlin-bom",
|
||||||
|
"version": {
|
||||||
|
"requires": "1.9.22"
|
||||||
|
},
|
||||||
|
"attributes": {
|
||||||
|
"org.gradle.category": "platform"
|
||||||
|
},
|
||||||
|
"endorseStrictVersions": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "org.jetbrains.kotlin",
|
||||||
|
"module": "kotlin-stdlib",
|
||||||
|
"version": {
|
||||||
|
"requires": "1.9.22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "org.jetbrains.kotlin",
|
||||||
|
"module": "kotlin-stdlib-jdk8",
|
||||||
|
"version": {
|
||||||
|
"requires": "1.9.22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "com.android.support",
|
||||||
|
"module": "multidex",
|
||||||
|
"version": {
|
||||||
|
"requires": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "net.zetetic",
|
||||||
|
"module": "android-database-sqlcipher",
|
||||||
|
"version": {
|
||||||
|
"requires": "4.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "androidx.sqlite",
|
||||||
|
"module": "sqlite-ktx",
|
||||||
|
"version": {
|
||||||
|
"requires": "2.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "org.whispersystems",
|
||||||
|
"module": "curve25519-android",
|
||||||
|
"version": {
|
||||||
|
"requires": "0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group": "org.whispersystems",
|
||||||
|
"module": "signal-protocol-android",
|
||||||
|
"version": {
|
||||||
|
"requires": "2.8.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"name": "WKIMLib_local-1.0.7.aar",
|
||||||
|
"url": "WKIMLib_local-1.0.7.aar",
|
||||||
|
"size": 619369,
|
||||||
|
"sha512": "67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d",
|
||||||
|
"sha256": "2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28",
|
||||||
|
"sha1": "d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8",
|
||||||
|
"md5": "195544eb25003c80879e6390c389f4b5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "releaseSourcesElements-published",
|
||||||
|
"attributes": {
|
||||||
|
"org.gradle.category": "documentation",
|
||||||
|
"org.gradle.dependency.bundling": "external",
|
||||||
|
"org.gradle.docstype": "sources",
|
||||||
|
"org.gradle.libraryelements": "jar",
|
||||||
|
"org.gradle.usage": "java-runtime",
|
||||||
|
"org.jetbrains.kotlin.platform.type": "androidJvm"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"name": "WKIMLib_local-1.0.7-sources.jar",
|
||||||
|
"url": "WKIMLib_local-1.0.7-sources.jar",
|
||||||
|
"size": 328517,
|
||||||
|
"sha512": "d1a0aa32976653fa04696f6d42edbe8152b59fdaf0135350cdefa14d571212571e85412c8f026a46e43069aadad3603358b63e262635a3716c948dab7b056750",
|
||||||
|
"sha256": "eb0a4ee07731a3ef38f606b2978d16169a6f6388e3f33fa3a10c82f3b0c17bb0",
|
||||||
|
"sha1": "34a3a10b015c40e16a76fe75cb974d675a9cbda6",
|
||||||
|
"md5": "2a8fa0fa06d069610eed09005b343994"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
18f875f433f4b46c3a8f82d2102b4efd
|
@ -0,0 +1 @@
|
|||||||
|
5e3e6e61712a9bee911ec2191da0faef05f93430
|
@ -0,0 +1 @@
|
|||||||
|
b5c54156b3a952972c75cfed1f5dd52419426a975df9a863efa8eb36f1feae12
|
@ -0,0 +1 @@
|
|||||||
|
0b3a1ba410c00e2566f0052b66121737164e4edc5defe64fd2aa7fd6e02ba05ccd9b2e0e13b603911d53a34ec9c10ee51fcd4c05719e19440c5da726484b45e3
|
@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<!-- This module was also published with a richer model, Gradle metadata, -->
|
||||||
|
<!-- which should be used instead. Do not delete the following line which -->
|
||||||
|
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
|
||||||
|
<!-- that they should prefer consuming it instead. -->
|
||||||
|
<!-- do_not_remove: published-with-gradle-metadata -->
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.xinbida.wukongim</groupId>
|
||||||
|
<artifactId>WKIMLib_local</artifactId>
|
||||||
|
<version>1.0.7</version>
|
||||||
|
<packaging>aar</packaging>
|
||||||
|
<name>WKIMLib</name>
|
||||||
|
<description>WuKong IM Android Library</description>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>The Apache License, Version 2.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-bom</artifactId>
|
||||||
|
<version>1.9.22</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>1.9.22</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
<version>1.9.22</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.android.support</groupId>
|
||||||
|
<artifactId>multidex</artifactId>
|
||||||
|
<version>1.0.3</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.zetetic</groupId>
|
||||||
|
<artifactId>android-database-sqlcipher</artifactId>
|
||||||
|
<version>4.5.4</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>androidx.sqlite</groupId>
|
||||||
|
<artifactId>sqlite-ktx</artifactId>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.whispersystems</groupId>
|
||||||
|
<artifactId>curve25519-android</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.whispersystems</groupId>
|
||||||
|
<artifactId>signal-protocol-android</artifactId>
|
||||||
|
<version>2.8.1</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1 @@
|
|||||||
|
ddc59ca3508344a630f0330f9c75801e
|
@ -0,0 +1 @@
|
|||||||
|
b351753e161fb1fde554f02adc966908b5d835b6
|
@ -0,0 +1 @@
|
|||||||
|
67367cbfa088cc2f2c57a66720e040865b70aa718b6f9487eeae174688b311f4
|
@ -0,0 +1 @@
|
|||||||
|
0ca8950dcf1398e81df06fb2c44015e10dac0d0ccc4d8db4e1e5eda302ee79c2727460d576f855c31bf8db5e669cdbb5d32897dce308009d069bc9e6d85126d9
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<metadata>
|
||||||
|
<groupId>com.xinbida.wukongim</groupId>
|
||||||
|
<artifactId>WKIMLib_local</artifactId>
|
||||||
|
<versioning>
|
||||||
|
<latest>1.0.7</latest>
|
||||||
|
<release>1.0.7</release>
|
||||||
|
<versions>
|
||||||
|
<version>1.0.7</version>
|
||||||
|
</versions>
|
||||||
|
<lastUpdated>20250524090841</lastUpdated>
|
||||||
|
</versioning>
|
||||||
|
</metadata>
|
@ -0,0 +1 @@
|
|||||||
|
2867162497a0539e3e3b0a1716f9feaa
|
@ -0,0 +1 @@
|
|||||||
|
e431ad1afdad3aff298476f1949e6dcb73bf52d2
|
@ -0,0 +1 @@
|
|||||||
|
aa7f10d602787f0faf2fc1a55c04fd089c55313b1d22c30cf1aa24c24ab9a216
|
@ -0,0 +1 @@
|
|||||||
|
3c7de45f238ee5d29b5c331b4c90ef396a87cc7a36550eeba7aa475e86f77da8d20e3373d177d46845e8e8d26c1ec106d2855ee1298c0763788a2583325b638f
|
@ -40,6 +40,8 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5/21/21 11:25 AM
|
* 5/21/21 11:25 AM
|
||||||
@ -102,20 +104,42 @@ public class MessageHandler {
|
|||||||
|
|
||||||
private volatile List<WKSyncMsg> receivedMsgList;
|
private volatile List<WKSyncMsg> receivedMsgList;
|
||||||
private final Object receivedMsgListLock = new Object();
|
private final Object receivedMsgListLock = new Object();
|
||||||
private final Object cacheLock = new Object();
|
private final ReentrantLock cacheLock = new ReentrantLock(true); // 使用公平锁
|
||||||
|
private static final long LOCK_TIMEOUT = 2000; // 2秒超时
|
||||||
private byte[] cacheData = null;
|
private byte[] cacheData = null;
|
||||||
private int available_len;
|
private int available_len;
|
||||||
|
|
||||||
public void clearCacheData() {
|
public void clearCacheData() {
|
||||||
synchronized (cacheLock) {
|
boolean locked = false;
|
||||||
cacheData = null;
|
try {
|
||||||
available_len = 0;
|
// 尝试获取锁,最多等待3秒
|
||||||
|
locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||||
|
if (locked) {
|
||||||
|
cacheData = null;
|
||||||
|
available_len = 0;
|
||||||
|
} else {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,clearCacheData失败");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "clearCacheData等待锁被中断: " + e.getMessage());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
cacheLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
synchronized void handlerOnlineBytes(INonBlockingConnection iNonBlockingConnection) {
|
synchronized void handlerOnlineBytes(INonBlockingConnection iNonBlockingConnection) {
|
||||||
synchronized (cacheLock) {
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,handlerOnlineBytes失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取可用数据长度
|
// 获取可用数据长度
|
||||||
available_len = iNonBlockingConnection.available();
|
available_len = iNonBlockingConnection.available();
|
||||||
@ -160,12 +184,26 @@ public class MessageHandler {
|
|||||||
WKLoggerUtils.getInstance().e(TAG, "onData 中发生意外错误: " + e.getMessage());
|
WKLoggerUtils.getInstance().e(TAG, "onData 中发生意外错误: " + e.getMessage());
|
||||||
clearCacheData();
|
clearCacheData();
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "handlerOnlineBytes等待锁被中断: " + e.getMessage());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
cacheLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void cutBytes(byte[] available_bytes,
|
synchronized void cutBytes(byte[] available_bytes,
|
||||||
IReceivedMsgListener mIReceivedMsgListener) {
|
IReceivedMsgListener mIReceivedMsgListener) {
|
||||||
synchronized (cacheLock) {
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,cutBytes失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cacheData == null || cacheData.length == 0) cacheData = available_bytes;
|
if (cacheData == null || cacheData.length == 0) cacheData = available_bytes;
|
||||||
else {
|
else {
|
||||||
//如果上次还存在未解析完的消息将新数据追加到缓存数据中
|
//如果上次还存在未解析完的消息将新数据追加到缓存数据中
|
||||||
@ -265,6 +303,13 @@ public class MessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveReceiveMsg();
|
saveReceiveMsg();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "cutBytes等待锁被中断: " + e.getMessage());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
cacheLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5/21/21 10:51 AM
|
* 5/21/21 10:51 AM
|
||||||
@ -146,9 +147,9 @@ public class WKConnection {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加一个专门用于同步connection访问的锁对象
|
// 替换原有的 Object 锁
|
||||||
public final Object connectionLock = new Object();
|
public final ReentrantLock connectionLock = new ReentrantLock(true); // 使用公平锁
|
||||||
|
private static final long LOCK_TIMEOUT = 3000; // 3秒超时
|
||||||
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
private final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
private static final long CONNECTION_CLOSE_TIMEOUT = 5000; // 5 seconds timeout
|
private static final long CONNECTION_CLOSE_TIMEOUT = 5000; // 5 seconds timeout
|
||||||
|
|
||||||
@ -548,15 +549,20 @@ public class WKConnection {
|
|||||||
|
|
||||||
//处理登录消息状态
|
//处理登录消息状态
|
||||||
private void handleLoginStatus(short status) {
|
private void handleLoginStatus(short status) {
|
||||||
WKLoggerUtils.getInstance().e(TAG, "Connection state transition: " + connectStatus + " -> " + status);
|
boolean locked = false;
|
||||||
|
try {
|
||||||
synchronized (connectionLock) {
|
locked = tryLockWithTimeout();
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,handleLoginStatus失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "Connection state transition: " + connectStatus + " -> " + status);
|
||||||
String reason = WKConnectReason.ConnectSuccess;
|
String reason = WKConnectReason.ConnectSuccess;
|
||||||
if (status == WKConnectStatus.kicked) {
|
if (status == WKConnectStatus.kicked) {
|
||||||
reason = WKConnectReason.ReasonAuthFail;
|
reason = WKConnectReason.ReasonAuthFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate state transition
|
|
||||||
if (!isValidStateTransition(connectStatus, status)) {
|
if (!isValidStateTransition(connectStatus, status)) {
|
||||||
WKLoggerUtils.getInstance().e(TAG, "Invalid state transition attempted: " + connectStatus + " -> " + status);
|
WKLoggerUtils.getInstance().e(TAG, "Invalid state transition attempted: " + connectStatus + " -> " + status);
|
||||||
return;
|
return;
|
||||||
@ -566,22 +572,22 @@ public class WKConnection {
|
|||||||
WKIM.getInstance().getConnectionManager().setConnectionStatus(status, reason);
|
WKIM.getInstance().getConnectionManager().setConnectionStatus(status, reason);
|
||||||
|
|
||||||
if (status == WKConnectStatus.success) {
|
if (status == WKConnectStatus.success) {
|
||||||
// Reset reconnection counters since we have a successful connection
|
|
||||||
connCount = 0;
|
connCount = 0;
|
||||||
isReConnecting = false;
|
isReConnecting = false;
|
||||||
|
|
||||||
// Set to syncing state
|
|
||||||
connectStatus = WKConnectStatus.syncMsg;
|
connectStatus = WKConnectStatus.syncMsg;
|
||||||
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.syncMsg, WKConnectReason.SyncMsg);
|
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.syncMsg, WKConnectReason.SyncMsg);
|
||||||
|
|
||||||
// Start timers and heartbeat before syncing
|
|
||||||
startAll();
|
startAll();
|
||||||
|
|
||||||
// Handle message syncing based on mode
|
|
||||||
if (WKIMApplication.getInstance().getSyncMsgMode() == WKSyncMsgMode.WRITE) {
|
if (WKIMApplication.getInstance().getSyncMsgMode() == WKSyncMsgMode.WRITE) {
|
||||||
WKIM.getInstance().getMsgManager().setSyncOfflineMsg((isEnd, list) -> {
|
WKIM.getInstance().getMsgManager().setSyncOfflineMsg((isEnd, list) -> {
|
||||||
if (isEnd) {
|
if (isEnd) {
|
||||||
synchronized (connectionLock) {
|
boolean innerLocked = false;
|
||||||
|
try {
|
||||||
|
innerLocked = tryLockWithTimeout();
|
||||||
|
if (!innerLocked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,setSyncOfflineMsg回调处理失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (connection != null && !isClosing.get()) {
|
if (connection != null && !isClosing.get()) {
|
||||||
connectStatus = WKConnectStatus.success;
|
connectStatus = WKConnectStatus.success;
|
||||||
MessageHandler.getInstance().saveReceiveMsg();
|
MessageHandler.getInstance().saveReceiveMsg();
|
||||||
@ -590,12 +596,22 @@ public class WKConnection {
|
|||||||
resendMsg();
|
resendMsg();
|
||||||
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
|
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (innerLocked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
WKIM.getInstance().getConversationManager().setSyncConversationListener(syncChat -> {
|
WKIM.getInstance().getConversationManager().setSyncConversationListener(syncChat -> {
|
||||||
synchronized (connectionLock) {
|
boolean innerLocked = false;
|
||||||
|
try {
|
||||||
|
innerLocked = tryLockWithTimeout();
|
||||||
|
if (!innerLocked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,setSyncConversationListener回调处理失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (connection != null && !isClosing.get()) {
|
if (connection != null && !isClosing.get()) {
|
||||||
connectStatus = WKConnectStatus.success;
|
connectStatus = WKConnectStatus.success;
|
||||||
WKIMApplication.getInstance().isCanConnect = true;
|
WKIMApplication.getInstance().isCanConnect = true;
|
||||||
@ -603,6 +619,10 @@ public class WKConnection {
|
|||||||
resendMsg();
|
resendMsg();
|
||||||
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
|
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (innerLocked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -612,13 +632,16 @@ public class WKConnection {
|
|||||||
WKIMApplication.getInstance().isCanConnect = false;
|
WKIMApplication.getInstance().isCanConnect = false;
|
||||||
stopAll();
|
stopAll();
|
||||||
} else {
|
} else {
|
||||||
// Only attempt reconnection if we're allowed to connect
|
|
||||||
if (WKIMApplication.getInstance().isCanConnect) {
|
if (WKIMApplication.getInstance().isCanConnect) {
|
||||||
reconnection();
|
reconnection();
|
||||||
}
|
}
|
||||||
WKLoggerUtils.getInstance().e(TAG, "Login status: " + status);
|
WKLoggerUtils.getInstance().e(TAG, "Login status: " + status);
|
||||||
stopAll();
|
stopAll();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,36 +678,46 @@ public class WKConnection {
|
|||||||
|
|
||||||
public void sendMessage(WKBaseMsg mBaseMsg) {
|
public void sendMessage(WKBaseMsg mBaseMsg) {
|
||||||
if (mBaseMsg == null) {
|
if (mBaseMsg == null) {
|
||||||
WKLoggerUtils.getInstance().w(TAG ,"sendMessage called with null mBaseMsg.");
|
WKLoggerUtils.getInstance().w(TAG, "sendMessage called with null mBaseMsg.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mBaseMsg.packetType != WKMsgType.CONNECT) {
|
|
||||||
if (connectStatus == WKConnectStatus.syncMsg) {
|
boolean locked = false;
|
||||||
WKLoggerUtils.getInstance().i(TAG ," sendMessage: In syncMsg status, message not sent: " + mBaseMsg.packetType);
|
try {
|
||||||
|
locked = tryLockWithTimeout();
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,sendMessage失败");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (connectStatus != WKConnectStatus.success) {
|
|
||||||
WKLoggerUtils.getInstance().w(TAG , " sendMessage: Not in success status (is " + connectStatus + "), attempting reconnection for: " + mBaseMsg.packetType);
|
if (mBaseMsg.packetType != WKMsgType.CONNECT) {
|
||||||
|
if (connectStatus == WKConnectStatus.syncMsg) {
|
||||||
|
WKLoggerUtils.getInstance().i(TAG, " sendMessage: In syncMsg status, message not sent: " + mBaseMsg.packetType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (connectStatus != WKConnectStatus.success) {
|
||||||
|
WKLoggerUtils.getInstance().w(TAG, " sendMessage: Not in success status (is " + connectStatus + "), attempting reconnection for: " + mBaseMsg.packetType);
|
||||||
|
reconnection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INonBlockingConnection currentConnection = this.connection;
|
||||||
|
if (currentConnection == null || !currentConnection.isOpen()) {
|
||||||
|
WKLoggerUtils.getInstance().w(TAG, " sendMessage: Connection is null or not open, attempting reconnection for: " + mBaseMsg.packetType);
|
||||||
reconnection();
|
reconnection();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
INonBlockingConnection currentConnection;
|
int status = MessageHandler.getInstance().sendMessage(currentConnection, mBaseMsg);
|
||||||
synchronized (connectionLock) {
|
if (status == 0) {
|
||||||
currentConnection = this.connection;
|
WKLoggerUtils.getInstance().e(TAG, "发消息失败 (status 0 from MessageHandler), attempting reconnection for: " + mBaseMsg.packetType);
|
||||||
}
|
reconnection();
|
||||||
|
}
|
||||||
if (currentConnection == null || !currentConnection.isOpen()) {
|
} finally {
|
||||||
WKLoggerUtils.getInstance().w(TAG ," sendMessage: Connection is null or not open, attempting reconnection for: " + mBaseMsg.packetType);
|
if (locked) {
|
||||||
reconnection();
|
connectionLock.unlock();
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
// Pass the local reference to MessageHandler
|
|
||||||
int status = MessageHandler.getInstance().sendMessage(currentConnection, mBaseMsg);
|
|
||||||
if (status == 0) {
|
|
||||||
WKLoggerUtils.getInstance().e(TAG, "发消息失败 (status 0 from MessageHandler), attempting reconnection for: " + mBaseMsg.packetType);
|
|
||||||
reconnection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void removeSendingMsg() {
|
private void removeSendingMsg() {
|
||||||
@ -846,8 +879,18 @@ public class WKConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean connectionIsNull() {
|
public boolean connectionIsNull() {
|
||||||
synchronized (connectionLock) {
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = tryLockWithTimeout();
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,connectionIsNull检查失败");
|
||||||
|
return true; // 保守起见,如果获取锁失败就认为连接为空
|
||||||
|
}
|
||||||
return connection == null || !connection.isOpen();
|
return connection == null || !connection.isOpen();
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,7 +926,14 @@ public class WKConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stopAll() {
|
public void stopAll() {
|
||||||
synchronized (connectionLock) {
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = tryLockWithTimeout();
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,stopAll失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 先设置连接状态为失败
|
// 先设置连接状态为失败
|
||||||
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.fail, "");
|
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.fail, "");
|
||||||
// 清理连接相关资源
|
// 清理连接相关资源
|
||||||
@ -912,6 +962,7 @@ public class WKConnection {
|
|||||||
connAckTime = 0;
|
connAckTime = 0;
|
||||||
lastMsgTime = 0;
|
lastMsgTime = 0;
|
||||||
connCount = 0;
|
connCount = 0;
|
||||||
|
|
||||||
// 清空发送消息队列
|
// 清空发送消息队列
|
||||||
if (sendingMsgHashMap != null) {
|
if (sendingMsgHashMap != null) {
|
||||||
sendingMsgHashMap.clear();
|
sendingMsgHashMap.clear();
|
||||||
@ -923,28 +974,38 @@ public class WKConnection {
|
|||||||
shutdownExecutor();
|
shutdownExecutor();
|
||||||
|
|
||||||
System.gc();
|
System.gc();
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeConnect() {
|
private void closeConnect() {
|
||||||
final INonBlockingConnection connectionToCloseActual;
|
final INonBlockingConnection connectionToCloseActual;
|
||||||
|
|
||||||
// 如果已经在关闭过程中,直接返回
|
|
||||||
if (!isClosing.compareAndSet(false, true)) {
|
if (!isClosing.compareAndSet(false, true)) {
|
||||||
WKLoggerUtils.getInstance().i(TAG , " Close operation already in progress");
|
WKLoggerUtils.getInstance().i(TAG, " Close operation already in progress");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (connectionLock) {
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = tryLockWithTimeout();
|
||||||
|
if (!locked) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁超时,closeConnect失败");
|
||||||
|
isClosing.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
isClosing.set(false);
|
isClosing.set(false);
|
||||||
WKLoggerUtils.getInstance().i(TAG , " closeConnect called but connection is already null.");
|
WKLoggerUtils.getInstance().i(TAG, " closeConnect called but connection is already null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connectionToCloseActual = connection;
|
connectionToCloseActual = connection;
|
||||||
String connId = connectionToCloseActual.getId();
|
String connId = connectionToCloseActual.getId();
|
||||||
|
|
||||||
// Mark connection for closure to prevent reconnection attempts
|
|
||||||
try {
|
try {
|
||||||
connectionToCloseActual.setAttachment("closing_" + System.currentTimeMillis() + "_" + connId);
|
connectionToCloseActual.setAttachment("closing_" + System.currentTimeMillis() + "_" + connId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -953,7 +1014,11 @@ public class WKConnection {
|
|||||||
|
|
||||||
connection = null;
|
connection = null;
|
||||||
connectionClient = null;
|
connectionClient = null;
|
||||||
WKLoggerUtils.getInstance().i(TAG , " Connection object nulled, preparing for async close of: " + connId);
|
WKLoggerUtils.getInstance().i(TAG, " Connection object nulled, preparing for async close of: " + connId);
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
connectionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a timeout handler to force close after timeout
|
// Create a timeout handler to force close after timeout
|
||||||
@ -961,7 +1026,7 @@ public class WKConnection {
|
|||||||
try {
|
try {
|
||||||
if (connectionToCloseActual.isOpen()) {
|
if (connectionToCloseActual.isOpen()) {
|
||||||
String connId = connectionToCloseActual.getId();
|
String connId = connectionToCloseActual.getId();
|
||||||
WKLoggerUtils.getInstance().w(TAG , " Connection close timeout reached for: " + connId);
|
WKLoggerUtils.getInstance().w(TAG, " Connection close timeout reached for: " + connId);
|
||||||
connectionToCloseActual.close();
|
connectionToCloseActual.close();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -979,13 +1044,13 @@ public class WKConnection {
|
|||||||
try {
|
try {
|
||||||
if (connectionToCloseActual.isOpen()) {
|
if (connectionToCloseActual.isOpen()) {
|
||||||
String connId = connectionToCloseActual.getId();
|
String connId = connectionToCloseActual.getId();
|
||||||
WKLoggerUtils.getInstance().i(TAG , " Attempting to close connection: " + connId);
|
WKLoggerUtils.getInstance().i(TAG, " Attempting to close connection: " + connId);
|
||||||
connectionToCloseActual.close();
|
connectionToCloseActual.close();
|
||||||
// Remove the timeout handler since we closed successfully
|
// Remove the timeout handler since we closed successfully
|
||||||
mainHandler.removeCallbacks(timeoutRunnable);
|
mainHandler.removeCallbacks(timeoutRunnable);
|
||||||
WKLoggerUtils.getInstance().i(TAG , " Successfully closed connection: " + connId);
|
WKLoggerUtils.getInstance().i(TAG, " Successfully closed connection: " + connId);
|
||||||
} else {
|
} else {
|
||||||
WKLoggerUtils.getInstance().i(TAG , " Connection was already closed or not open when async close executed: " + connectionToCloseActual.getId());
|
WKLoggerUtils.getInstance().i(TAG, " Connection was already closed or not open when async close executed: " + connectionToCloseActual.getId());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
WKLoggerUtils.getInstance().e(TAG, "IOException during async connection close for " + connectionToCloseActual.getId() + ": " + e.getMessage());
|
WKLoggerUtils.getInstance().e(TAG, "IOException during async connection close for " + connectionToCloseActual.getId() + ": " + e.getMessage());
|
||||||
@ -1008,4 +1073,14 @@ public class WKConnection {
|
|||||||
closeThread.setDaemon(true);
|
closeThread.setDaemon(true);
|
||||||
closeThread.start();
|
closeThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean tryLockWithTimeout() {
|
||||||
|
try {
|
||||||
|
return connectionLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
WKLoggerUtils.getInstance().e(TAG, "获取锁被中断: " + e.getMessage());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user