fix: 去抖改为暂存合并,不丢弃消息

问题:多条MQTT消息同时到达(间隔<1s),去抖直接丢弃后续消息。
旧版是延迟处理而非丢弃。

修复:
- 去抖窗口内的消息暂存到pendingJsons
- 1s后延迟任务统一处理暂存消息(只加ID,不重复震动)
- 合并后统一发一次NewTaskArrived事件更新横幅
- MainActivity改为监听NewTaskArrived事件显示横幅

时序示例:
t=0ms:   消息1(A) → 立即处理, pendingTaskIds=[A], 横幅"1条"
t=100ms: 消息2(B) → 暂存
t=200ms: 消息3(C) → 暂存
t=1000ms: 延迟任务 → 处理B+C, pendingTaskIds=[A,B,C], 横幅"3条"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dongliang
2026-04-29 15:27:06 +09:30
parent 1ffdefc887
commit 379d784f70
3 changed files with 79 additions and 41 deletions

View File

@@ -47,6 +47,12 @@ class NotificationManager @Inject constructor(
/** 上次消息处理时间(去抖用) */
private var lastMessageTime = 0L
/** 去抖窗口内暂存的消息(延迟合并处理,不丢弃) */
private val pendingJsons = mutableListOf<String>()
/** 去抖延迟任务 */
private var debounceJob: kotlinx.coroutines.Job? = null
/** 上次统计数据(对比红点用) */
var lastStats: TaskStatistics? = null
@@ -55,46 +61,80 @@ class NotificationManager @Inject constructor(
/**
* 处理 MQTT type=1 新任务消息
* 去抖策略1s 窗口内的消息暂存,窗口结束后合并处理(不丢弃)
* @param rawJson MQTT 消息原始 JSON
* @return true=已处理false=被去抖过滤
*/
fun onNewTaskMessage(rawJson: String): Boolean {
// 1. 去抖1s 内重复消息忽略
fun onNewTaskMessage(rawJson: String) {
val now = System.currentTimeMillis()
if (now - lastMessageTime < DEBOUNCE_MS) {
Timber.d("通知: 去抖过滤 (距上条 ${now - lastMessageTime}ms)")
return false
// 去抖窗口内 → 暂存,等延迟任务统一处理
pendingJsons.add(rawJson)
Timber.d("通知: 去抖暂存 (已暂存 ${pendingJsons.size} 条)")
return
}
// 窗口外 → 立即处理本条 + 启动延迟任务处理后续暂存
lastMessageTime = now
processMessage(rawJson)
// 2. 解析任务 ID
val taskIds = parseTaskIds(rawJson)
if (taskIds.isEmpty()) {
Timber.w("通知: 消息中无有效任务 ID")
return false
}
// 3. 加入未读列表(去重)
for (id in taskIds) {
if (id !in _pendingTaskIds) {
_pendingTaskIds.add(id)
// 启动延迟任务1s 后处理暂存的消息
debounceJob?.cancel()
debounceJob = scope.launch {
kotlinx.coroutines.delay(DEBOUNCE_MS)
if (pendingJsons.isNotEmpty()) {
Timber.d("通知: 处理暂存的 ${pendingJsons.size} 条消息")
val jsons = pendingJsons.toList()
pendingJsons.clear()
lastMessageTime = System.currentTimeMillis()
for (json in jsons) {
processMessageSilent(json) // 只加 ID不重复震动
}
// 合并后统一发一次事件
notifyUi()
}
}
Timber.d("通知: 收到 ${taskIds.size} 个新任务, 当前未读 ${_pendingTaskIds.size}")
}
// 4. 震动 + 亮屏
/** 处理单条消息(完整:解析+震动+亮屏+事件) */
private fun processMessage(rawJson: String) {
val taskIds = parseTaskIds(rawJson)
if (taskIds.isEmpty()) return
addTaskIds(taskIds)
// 震动 + 亮屏(只在首条时触发,暂存的合并后不重复震动)
val pattern = VibrationDefaults.getPattern(PLAN_NEW_MESSAGE)
if (pattern != null) {
vibrationController.executePattern(pattern)
}
screenController.turnOn()
// 5. 发送事件通知
scope.launch {
eventBus.emit(AppEvent.NewTaskArrived(taskIds, _pendingTaskIds.size))
}
notifyUi()
}
return true
/** 静默处理(只加 ID不震动不亮屏用于合并暂存消息 */
private fun processMessageSilent(rawJson: String) {
val taskIds = parseTaskIds(rawJson)
if (taskIds.isEmpty()) return
addTaskIds(taskIds)
}
/** 加入未读列表(去重) */
private fun addTaskIds(taskIds: List<String>) {
for (id in taskIds) {
if (id !in _pendingTaskIds) {
_pendingTaskIds.add(id)
}
}
Timber.d("通知: 当前未读 ${_pendingTaskIds.size}")
}
/** 通知 UI 更新(横幅+红点) */
private fun notifyUi() {
scope.launch {
eventBus.emit(AppEvent.NewTaskArrived(_pendingTaskIds.toList(), _pendingTaskIds.size))
}
}
/** 消费所有未读消息(用户已查看列表) */