fix: 点击连接按钮后立即启动心跳线程,不再等待数据包接收
ProtocolClient.connect() 现在立即启动心跳循环(1Hz),而不是 等到 receiveLoop 首次收到数据包后才启动。心跳在 CONNECTING 和 CONNECTED 状态下均正常运行,确保连接建立过程中机器人能持续收到 心跳包。 Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -211,6 +211,7 @@ gradlew installDebug
|
||||
- [x] 连接状态准确性修复:`ProtocolClient` 收到首个有效数据包后才标记 `CONNECTED`,不再 socket 创建后立即标记;`CONNECTING` 状态 5 秒无响应自动超时回退 `TIMEOUT`
|
||||
- [x] 连接按钮交互优化:`CONNECTING` 状态下点击连接按钮仅断开回到 `DISCONNECTED`,不再自动重连,由用户手动再次点击发起重试
|
||||
- [x] 状态机补充:`RobotConnection` 允许 `CONNECTING → TIMEOUT` 合法转换
|
||||
- [x] 心跳启动时机修复:`ProtocolClient.connect()` 立即启动心跳线程,不再等待首次收到数据包后才启动;心跳在 `CONNECTING` 和 `CONNECTED` 状态下均正常运行
|
||||
|
||||
### 待办
|
||||
|
||||
|
||||
@@ -92,7 +92,8 @@ class ProtocolClient(
|
||||
* 2. 启动接收/发送协程
|
||||
* 3. 发送订阅请求
|
||||
* 4. 启动断线检测(CONNECTING 5s / CONNECTED 3s 无数据 → TIMEOUT)
|
||||
* 5. 首次收到有效数据包后标记已连接,并启动心跳 1Hz(在接收循环中处理)
|
||||
* 5. 启动心跳 1Hz(立即发送,覆盖 CONNECTING 和 CONNECTED 状态)
|
||||
* 6. 首次收到有效数据包后标记已连接
|
||||
*/
|
||||
fun connect() {
|
||||
if (_state.value != State.DISCONNECTED && _state.value != State.ERROR) return
|
||||
@@ -136,6 +137,11 @@ class ProtocolClient(
|
||||
timeoutJob = scope.launch {
|
||||
timeoutCheckLoop()
|
||||
}
|
||||
|
||||
// 启动心跳(立即开始,覆盖 CONNECTING 和 CONNECTED 状态)
|
||||
heartbeatJob = scope.launch(Dispatchers.IO) {
|
||||
heartbeatLoop(sock, address)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_state.value = State.ERROR
|
||||
closeSocket()
|
||||
@@ -227,12 +233,9 @@ class ProtocolClient(
|
||||
_statusReport.tryEmit(report)
|
||||
}
|
||||
|
||||
// 首次收到有效数据包:标记已连接,启动心跳
|
||||
// 首次收到有效数据包:标记已连接
|
||||
if (_state.value == State.CONNECTING) {
|
||||
_state.value = State.CONNECTED
|
||||
heartbeatJob = scope.launch(Dispatchers.IO) {
|
||||
heartbeatLoop(sock, remoteAddress!!)
|
||||
}
|
||||
}
|
||||
} catch (_: SocketTimeoutException) {
|
||||
// 超时正常,继续循环
|
||||
@@ -246,9 +249,11 @@ class ProtocolClient(
|
||||
}
|
||||
}
|
||||
|
||||
/** 心跳循环(1 Hz) */
|
||||
/** 心跳循环(1 Hz)—— 在 CONNECTING 和 CONNECTED 状态下运行 */
|
||||
private suspend fun CoroutineScope.heartbeatLoop(sock: DatagramSocket, address: InetAddress) {
|
||||
while (isActive && _state.value == State.CONNECTED) {
|
||||
while (isActive &&
|
||||
(_state.value == State.CONNECTING || _state.value == State.CONNECTED)
|
||||
) {
|
||||
try {
|
||||
val json = ControlCommands.heartbeat()
|
||||
val packet = encoder.encode(json)
|
||||
|
||||
Reference in New Issue
Block a user