Flutter Riverpod中Appwrite实时订阅取消订阅时的Missing channels(1008)问题
问题分析
你遇到的是Flutter结合Riverpod使用Appwrite实时订阅时的异常:单文档订阅功能正常,但多文档订阅场景下,页面关闭导致autoDispose Provider销毁时,Appwrite抛出Missing channels (1008)未处理异常。错误日志明确指向Realtime通道缺失问题。
已知前提
- 所有订阅文档均存在于目标集合,用户拥有读取权限
- Appwrite实例为全局单例,无重复实例
可能原因
当多个TestNotifier实例(对应不同文档)共享同一个Appwrite Realtime单例时,多订阅的close()操作存在异步竞态:某一个订阅关闭后,后续其他订阅的关闭请求可能尝试移除已不存在的通道,或因Realtime连接状态变化触发通道校验失败。
解决方案
方案1:捕获close操作的异常
在dispose方法中用try-catch包裹订阅关闭逻辑,忽略已知的通道缺失异常:
@override void dispose() { if (_subscription != null) { try { _subscription?.close(); } on AppwriteException catch (e) { // 仅忽略1008通道缺失异常,其他异常正常抛出 if (e.code != 1008) rethrow; } } super.dispose(); }
方案2:改用集合级订阅(推荐)
放弃为每个文档创建独立订阅,改为订阅整个集合并在本地过滤目标文档,减少Realtime连接数并避免多订阅关闭冲突:
void subscribe() { final realtime = ref.watch(AppwriteDependencies.realtime); // 订阅整个stats集合的所有文档变更 _subscription = realtime.subscribe(['databases.bracket_db.collections.stats.documents']); _subscription?.stream.listen((response) { // 仅处理当前Provider关注的文档ID if (response.payload['\$id'] == docID) { final bracketStats = BracketStats.fromJson(response.payload); state = bracketStats; } }); }
这种方式下,无论多少个Provider实例,都共享同一个Realtime连接,仅在本地过滤数据,从根源避免多订阅关闭的通道冲突问题。
方案3:稳定Realtime实例生命周期
确保AppwriteDependencies.realtime提供的是非autoDispose的全局单例Provider,保证Realtime实例在所有订阅Provider销毁前始终存在,避免因实例提前销毁导致的通道操作失败。
验证建议
- 测试多文档场景下的页面关闭流程,确认异常是否消失
- 查看Appwrite控制台的Realtime连接统计,验证方案2的连接数是否符合预期(仅1个集合连接)
内容的提问来源于stack exchange,提问作者monzim
相关产品推荐
相关产品推荐

