You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter JS-Interop中StreamController无法从ListProvider更新值问题

问题分析与解决方案

问题原因

  1. 引用类型覆盖问题:你在循环中修改的是同一个Uint8List实例,由于它是引用类型,后续循环的修改会直接覆盖之前实例的内容。当StreamController发送这个实例时,最终所有发送的都是循环结束时的最终值。
  2. build方法的不当使用:在build方法中处理发送数据的业务逻辑不合适,build会因多种原因触发重绘,可能导致重复发送或逻辑执行混乱。

解决方案

1. 循环中创建独立的Uint8List实例

每次需要发送时,创建新的Uint8List实例,避免复用同一个引用:

for (int i = 0; i < 8; i++) {
  final buttonState = ref.read(listProvider1)[i][currentStep];
  if (buttonState) {
    // 创建新的Uint8List实例,基于需求修改值
    final newList = Uint8List.fromList([144, 30 + i, 70]);
    ref.read(listProvider3.notifier).state = newList;
    sendToJs(newList); // 直接传入新实例
  }
}

2. 将发送逻辑移出build方法,使用ref.listen监听状态变化

在initState或ConsumerState的build外,通过ref.listen监听steplistProvider的变化,避免在build中执行业务逻辑:

@override
void initState() {
  super.initState();
  // 监听步进序号的变化,触发发送逻辑
  ref.listen(steplistProvider, (previous, currentStep) {
    final buttonMatrix = ref.read(listProvider1);
    for (int i = 0; i < 8; i++) {
      if (buttonMatrix[i][currentStep]) {
        final newList = Uint8List.fromList([144, 30 + i, 70]);
        ref.read(listProvider3.notifier).state = newList;
        _streamController.add(newList); // 发送独立的新实例
      }
    }
  });
}

3. 确保StreamController发送的是独立副本

如果必须复用某个基础列表,每次发送前创建副本:

// 发送前创建副本,避免后续修改影响已发送的数据
final sendList = Uint8List.fromList(listBytes);
_streamController.add(sendList);

额外建议

  • 避免在build方法中执行状态更新、数据发送这类副作用操作,应该将这类逻辑放到状态监听、事件回调或专门的业务逻辑类中。
  • 可以考虑将WebMidi的发送逻辑封装成单独的Provider(比如StateNotifierProvider),统一管理发送状态和逻辑,提高代码的可维护性。

内容的提问来源于stack exchange,提问作者sensn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 23:50:14