簡體   English   中英

Flutter Riverpod:使用 StreamProvider 返回 2 stream

[英]Flutter Riverpod : return 2 stream with StreamProvider

我有使用 package資產音頻播放器Flutter Riverpod作為 State 管理的音樂播放器應用程序。 我想聽兩件事 stream:

  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 stream 返回到 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'),
                );
               
              },
            ),

我將從為每個Stream創建一個StreamProvider開始:

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,
  };
});

最后,創建一個StreamProviderdurationInfo轉換為Stream

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

這個答案是@AlexHartford 所做的另一種方法。

我的案例的當前解決方案是使用 package rxdart CombineLatestStream.list() ,然后應該查看此代碼:

流提供者

final currentSongPosition = StreamProvider.autoDispose((ref) {
  final AssetsAudioPlayer player = ref.watch(globalAudioPlayers).state;

  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 tempList = [_first, _second];
  return CombineLatestStream.list(tempList);
});

如何使用它:

Consumer(
              builder: (_, watch, __) {
                final players = watch(globalAudioPlayers).state;
                final _currentSong = watch(currentSongPosition);
                return _currentSong.when(
                  data: (value) {
                    final _currentDuration = value[0];
                    final _maxDuration = value[1];
                    return Slider.adaptive(
                      value: _currentDuration,
                      max: _maxDuration,
                      onChanged: (value) async {
                        final newDuration = Duration(seconds: value.toInt());
                        await players.seek(newDuration);
                        context.read(currentSongProvider).setDuration(newDuration);
                      },
                    );
                  },
                  loading: () => const Center(child: CircularProgressIndicator()),
                  error: (error, stackTrace) => Text(error.toString()),
                );
              },
            ),

但是這種方法有缺點,代碼難以閱讀。 特別是在Consumer中使用時,我必須知道返回結果的順序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM