Flutter Swift StreamHandler处理多监听器时如何移除对应FlutterEventSink
解决方案
核心问题:FlutterStreamHandler的onCancel回调仅会携带和对应onListen一致的arguments参数,不会回传要移除的FlutterEventSink实例,且Swift原生无法直接比较闭包相等,所以需要将arguments与对应的sink绑定存储,才能在onCancel时精准匹配移除。
实现逻辑
- 修改存储结构,将单纯的sink数组改为存储
(参数标识: AnyHashable, 事件回调: FlutterEventSink)的集合 onListen时把传入的arguments转为可哈希类型,和sink配对后存入集合onCancel时用传入的arguments作为标识,匹配移除对应的sink项- 增加串行队列保证集合操作的线程安全,避免多线程操作出现崩溃
修改后的完整代码
class ConnectionStateStreamHandler: NSObject, DeviceConnectionDelegate, FlutterStreamHandler { var plugin: WearablePlugin? = nil // 元组数组支持同一参数对应多个监听,也可改用[AnyHashable: FlutterEventSink]字典做单监听限制 private var eventSinks: [(key: AnyHashable, sink: FlutterEventSink)] = [] // 串行队列做线程安全保护 private let operationQueue = DispatchQueue(label: "com.wearableplugin.connectionStreamQueue") func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { operationQueue.sync { guard let key = arguments as? AnyHashable else { return FlutterError(code: "INVALID_ARGUMENTS", message: "监听参数必须为可哈希类型", details: nil) } eventSinks.append((key: key, sink: events)) return nil } } func onCancel(withArguments arguments: Any?) -> FlutterError? { operationQueue.sync { guard let key = arguments as? AnyHashable else { return FlutterError(code: "INVALID_ARGUMENTS", message: "监听参数必须为可哈希类型", details: nil) } // 精准移除对应标识的所有sink eventSinks.removeAll { $0.key == key } return nil } } func onConnectionStateChanged(device: Device, connectionState: ConnectionState) { operationQueue.sync { guard let data = try? jsonEncoder.encode(device), let jsonStr = String(data: data, encoding: .utf8) else { return } eventSinks.forEach { $0.sink(jsonStr) } } } }
补充说明
- 如果不需要支持同一个参数对应多个监听,直接用
[AnyHashable: FlutterEventSink]字典存储即可,onListen直接赋值、onCancel直接调用removeValue(forKey:),性能更高。 - 如果业务不需要传递自定义参数,可以要求Flutter端每次调用
listen时生成一个唯一UUID作为参数传入,即可实现无业务参数下的精准匹配移除。 - 原代码中的强制解析
try!建议替换为try?加空判断,避免编码失败导致应用崩溃。
内容的提问来源于stack exchange,提问作者toonvanstrijp
相关产品推荐
相关产品推荐

