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

如何在Riverpod中获取Stream Provider的连接状态?

用Riverpod实现模块逐个加载并显示完成提示

一、当前写法的小问题

你当前代码里循环渲染模块时用了modules[i],逻辑上应该改用value[i](或直接遍历value)。因为value是Stream当前输出的已加载模块列表,这样更符合数据流逻辑,能避免原始列表和流输出不一致时出现错误。

二、判断Stream是否完成的两种方案

方案1:自定义状态类,包含加载状态和完成标记

这种方法直接在Stream输出中包含完成状态,逻辑紧凑,适合单一组件使用场景。

1. 定义状态类

class ModuleLoadState {
  final List<String> loadedModules;
  final bool isDone;

  ModuleLoadState(this.loadedModules, this.isDone);
}

2. 修改StreamProvider

@riverpod
Stream<ModuleLoadState> getModules(Ref ref, List<String> modules) async* {
  final showingModules = <String>[];

  for (var module in modules) {
    await Future.delayed(const Duration(milliseconds: 1500));
    showingModules.add(module);
    // 每次加载一个模块后,输出未完成状态
    yield ModuleLoadState(List.unmodifiable(showingModules), false);
  }
  // 所有模块加载完成后,输出标记为完成的状态
  yield ModuleLoadState(List.unmodifiable(showingModules), true);
}

3. 渲染Widget

Consumer(
  builder: (context, ref, child) {
    final moduleState = ref.watch(getModulesProvider(modules));
    return switch (moduleState) {
      AsyncData(:final value) => Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 遍历已加载模块
            for (final module in value.loadedModules) ...[
              Row(
                children: [
                  Container(
                    width: 8,
                    height: 8,
                    decoration: ShapeDecoration(
                      shape: const CircleBorder(),
                      color: primary,
                    ),
                  ),
                  const SizedBox(width: 4),
                  LeftToRightTextFade(text: module),
                ],
              ),
              const SizedBox(height: 8),
            ],
            // 流完成后显示提示
            if (value.isDone) ...[
              const SizedBox(height: 16),
              FutureBuilder(
                future: Future.delayed(const Duration(milliseconds: 500)),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    return Text(
                      "All modules loaded...",
                      style: body(context).copyWith(color: primary),
                    );
                  }
                  return const SizedBox.shrink();
                },
              ),
            ]
          ],
        ),
      AsyncError(:final error) => Text('加载出错: $error'),
      AsyncLoading() => const SizedBox.shrink(),
    };
  },
),

方案2:用单独的StateProvider标记完成状态

这种方法将完成状态与数据流分离,适合需要在多个组件中复用完成状态的场景。

1. 创建状态Provider和StreamProvider

// 标记所有模块是否加载完成的状态Provider
@riverpod
StateProvider<bool> modulesLoadCompleted(Ref ref) => StateProvider((ref) => false);

@riverpod
Stream<List<String>> getModules(Ref ref, List<String> modules) async* {
  final showingModules = <String>[];
  final completedNotifier = ref.read(modulesLoadCompletedProvider.notifier);

  try {
    for (var module in modules) {
      await Future.delayed(const Duration(milliseconds: 1500));
      showingModules.add(module);
      yield List.unmodifiable(showingModules);
    }
  } finally {
    // 流完成时更新状态
    completedNotifier.state = true;
  }
}

2. 渲染Widget

Consumer(
  builder: (context, ref, child) {
    final loadedModules = ref.watch(getModulesProvider(modules));
    final isLoadCompleted = ref.watch(modulesLoadCompletedProvider);
    
    return switch (loadedModules) {
      AsyncData(:final value) => Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            for (final module in value) ...[
              Row(
                children: [
                  Container(
                    width: 8,
                    height: 8,
                    decoration: ShapeDecoration(
                      shape: const CircleBorder(),
                      color: primary,
                    ),
                  ),
                  const SizedBox(width: 4),
                  LeftToRightTextFade(text: module),
                ],
              ),
              const SizedBox(height: 8),
            ],
            if (isLoadCompleted) ...[
              const SizedBox(height: 16),
              FutureBuilder(
                future: Future.delayed(const Duration(milliseconds: 500)),
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    return Text(
                      "All modules loaded...",
                      style: body(context).copyWith(color: primary),
                    );
                  }
                  return const SizedBox.shrink();
                },
              ),
            ]
          ],
        ),
      AsyncError(:final error) => Text('加载出错: $error'),
      AsyncLoading() => const SizedBox.shrink(),
    };
  },
),

三、注意事项

  • 用List.unmodifiable包装输出列表,避免外部修改导致状态不一致。
  • 若需要支持重新加载模块,可在Provider中添加ref.onDispose或监听依赖变化重置状态。

内容的提问来源于stack exchange,提问作者Sireen Ibnu Kabeer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:05:58