removeTimCallbackFromMap static method

void removeTimCallbackFromMap(
  1. String userData
)

从 _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);
}