首页 > 解决方案 > Flutter Riverpod:使用 StreamProvider 返回 2 个流

问题描述

我有使用包Asset Audio PlayerFlutter Riverpod作为状态管理的音乐播放器应用程序。我想听两件事流:

  1. 收听歌曲的当前时长
  2. 收听当前播放的歌曲
final currentSongPosition = StreamProvider.autoDispose<Map<String, dynamic>>((ref) async* {
  final AssetsAudioPlayer player = ref.watch(globalAudioPlayers).state;
  ref.onDispose(() => player.dispose());

  final Stream<double> _first = player.currentPosition.map((event) => event.inSeconds.toDouble());
  final Stream<double> _second =
      player.current.map((event) => event?.audio.duration.inSeconds.toDouble() ?? 0.0);

  final maps = {};
  maps['currentDuration'] = _first;
  maps['maxDurationSong'] = _second;
  return maps; << Error The return type 'Map<dynamic, dynamic>' isn't a 'Stream<Map<String, dynamic>>', as required by the closure's context.
});

如何将 2 个流返回 1 StreamProvider,然后我可以像这样简单地使用:

Consumer(
              builder: (_, watch, __) {
               
                final _currentSong = watch(currentSongPosition);

                return _currentSong.when(
                  data: (value) {
                    final _currentDuration = value['currentDuration'] as double;
                    final _maxDuration = value['maxDuration'] as double;
                    return Text('Current : $_currentDuration, Max :$_maxDuration');
                  },
                  loading: () => Center(child: CircularProgressIndicator()),
                  error: (error, stackTrace) => Text('Error When Playing Song'),
                );
               
              },
            ),

标签: flutterdartriverpod

解决方案


我将首先StreamProvider为每个创建一个Stream

final currentDuration = StreamProvider.autoDispose<double>((ref) {
  final player = ref.watch(globalAudioPlayers).state;
  return player.currentPosition.map((event) => event.inSeconds.toDouble());
});

final maxDuration = StreamProvider.autoDispose<double>((ref) {
  final player = ref.watch(globalAudioPlayers).state;
  return player.current.map((event) => event?.audio.duration.inSeconds.toDouble() ?? 0.0);
});

接下来,创建一个FutureProvider来读取每个的最后一个值Stream

final durationInfo = FutureProvider.autoDispose<Map<String, double>>((ref) async {
  final current = await ref.watch(currentDuration.last);
  final max = await ref.watch(maxDuration.last);
  return {
    'currentDuration': current,
    'maxDurationSong': max,
  };
});

最后,创建一个StreamProvider转换durationInfoStream.

final currentSongPosition = StreamProvider.autoDispose<Map<String, double>>((ref) {
  final info = ref.watch(durationInfo.future);
  return info.asStream();
});

推荐阅读