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:
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
/** 消费所有未读消息(用户已查看列表) */
|
||||
|
||||
Reference in New Issue
Block a user