HarmonyOS 7 外设上线回调重复怎么办?PartnerAgentExtensionAbility 去重与延迟销毁
HarmonyOS 7 外设上线回调重复怎么办?PartnerAgentExtensionAbility 去重与延迟销毁
同一块手表在页面里出现两次,不一定是扫描错了。PartnerAgentExtensionAbility 可能因 BLE 扫描或 ACL 连接收到设备发现信号;如果每个回调都追加列表,就会把状态更新误当成新设备。

先确认 API 26 的能力边界
官方指南说明 onDeviceDiscovered 可由扫描发现或连接成功触发;设备断开后 Extension 进程延迟约三分钟销毁;onDestroyWithReason 是最终清理资源的重要信号。
- 发现事件应按设备身份 upsert,不应直接 append。
- 在线状态与 Extension 进程是否仍存活是两个概念。
- 资源清理必须幂等,允许多个退出路径重复调用。
案例一:扫描和连接各回调一次,列表出现两个相同设备
先规范化地址格式与 addressType,再生成会话键。若产品提供更稳定的设备标识,应优先使用产品标识。
interface Address { address?: string; addressType?: number }
function deviceKey(input: Address): string {
const value = (input.address || '').trim().toUpperCase().replace(/-/g, ':')
if (!/^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(value)) throw new Error('地址无效')
return String(input.addressType ?? -1) + '|' + value
}
console.assert(deviceKey({ address: 'aa-bb-cc-dd-ee-ff', addressType: 1 }) === '1|AA:BB:CC:DD:EE:FF')
格式差异不会再创建第二个会话,同时 seenCount 仍可记录回调次数用于排查。
案例二:蓝牙一断开就清空全部状态,短时间重连反复初始化
进程延迟销毁不代表设备仍在线。状态应区分 online、grace 和 destroyed;最终资源释放以系统销毁回调为准。
type Phase = 'online' | 'grace' | 'destroyed'
interface Life { phase: Phase; disconnectedAt?: number }
function shouldRelease(state: Life, now: number, grace = 180000): boolean {
return state.phase === 'grace' && state.disconnectedAt !== undefined && now - state.disconnectedAt >= grace
}
const state: Life = { phase: 'grace', disconnectedAt: 1000 }
console.assert(!shouldRelease(state, 180999))
console.assert(shouldRelease(state, 181000))
宽限期内设备显示离线但可保留必要会话信息,系统真正销毁时再执行幂等清理。
现象与判断对照
| 现象 | 优先检查 | 处理原则 |
|---|---|---|
| 同一设备出现两次 | 地址归一化与 upsert | 更新同一会话 |
| 断开后仍显示在线 | 在线与进程存活是否混用 | 拆分 phase |
| 三分钟内重连很慢 | 是否过早销毁全部缓存 | 保留可复用状态 |
| 页面退出后仍有任务 | 销毁回调是否清理 | 幂等释放资源 |
为什么选择这个实现
事件去重不是丢弃第二次回调,而是把回调合并为同一会话的状态更新。这样既不重复显示,也保留了调试所需的发现次数和时间。
可复用边界
设备注册表可复用到手表、耳机等伙伴设备;设备身份策略必须允许产品层替换,不能把蓝牙地址永久写死成唯一账号标识。
验证记录
已验证地址大小写与分隔符归一化、重复发现只保留一个会话、179999ms 不释放、180000ms 到期以及重复 cleanup 不抛错。
本文的策略代码已在宿主 JavaScript 环境执行断言,用来验证状态、排序、去重或边界计算。它不等同于 HarmonyOS 7 API 26 工程编译,也不等同于真机系统能力验证;涉及系统回调、设备能力、窗口形态或跨应用 IPC 的部分,仍应在对应 SDK 与设备上完成端到端验收。
上线前检查清单
- 设备身份键来源明确
- 发现事件使用 upsert
- 在线与进程存活分开
- 宽限期内 UI 显示离线
- onDestroyWithReason 幂等清理
- 真实伙伴设备完成扫描和断连测试
官方资料
发现回调是会话更新信号,销毁回调才是资源释放边界。把这两件事分开,重复设备和重连抖动会一起减少。
更多推荐



所有评论(0)