removeTimCallbackFromMap static method
从 _apiCallbackMap 移除指定 userData 的 closure。
务必在调用方挂 completer.future.whenComplete(...) 来调用本函数,即使
_handleNativeCallback 内部已经先 remove 过一次。
原因:completer 完成有三条互相独立的路径,需要两套 remove 协作覆盖:
┌──────────────────────────────────┬──────────────────────────────┬──────────────────────────────┐
│ 完成路径 │ 由谁触发 completer.complete │ 由谁清理 _apiCallbackMap │
├──────────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ ① native 主动回调(正常路径) │ closure 内 completer.complete│ _handleNativeCallback 同步 remove │
│ ② 调用方失败早返主动 complete │ 调用方 completer.complete │ 调用方 whenComplete remove │
│ (如 result != TIM_SUCC 分支)│ (failResult) │ │
│ ③ 调用方超时主动 complete │ Timer 触发 completer.complete│ 调用方 whenComplete remove │
│ (如 callExperimentalAPI) │ (timeoutResult) │ │
└──────────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
路径 ① 下,等到 whenComplete 微任务跑到时 map 早已被 remove,这次 remove 是 no-op,无害;但路径 ② / ③ 下 closure 从未被 _handleNativeCallback 取出, 必须靠 whenComplete 的 remove 兜底,否则 closure 永久驻留 map,造成内存泄漏。
因此请记住:_handleNativeCallback 里那次 remove 不是唯一清理点;
调用方的 whenComplete 也不是"冗余的兜底",而是覆盖另一类 completion 路径
的必需清理。两者互补,缺一不可。
Implementation
static void removeTimCallbackFromMap(String userData) {
_apiCallbackMap.remove(userData);
}