Flutter Riverpod:使用 StreamProvider 返回 2 个流
Posted
技术标签:
【中文标题】Flutter Riverpod:使用 StreamProvider 返回 2 个流【英文标题】:Flutter Riverpod : return 2 stream with StreamProvider 【发布时间】:2021-08-02 21:19:49 【问题描述】:我有使用包Asset Audio Player 和Flutter Riverpod 作为状态管理的音乐播放器应用程序。我想听两件事:
-
收听歌曲的当前时长
收听当前播放的歌曲
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'),
);
,
),
【问题讨论】:
您应该将答案添加为答案,而不是作为问题的编辑。 另外,我的回答没有用吗?它解决了您对使用 rxdart 的解决方案提出的担忧。 @AlexHartford 你的回答和我预期的一样,我只是在我的问题中添加了另一种方法。 @AlexHartford 我对我的案例的最佳实践感到好奇,最好像您的方法那样分离 StreamProvider ,或者我们可以使用我的方法吗?我的问题的重点是,它更多是关于代码效率 我不能保证我的答案是“最佳实践”,但它是解决问题的持久、易于理解的方法。 【参考方案1】:我会首先为每个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,
;
);
最后,创建一个StreamProvider
,将durationInfo
转换为Stream
。
final currentSongPosition = StreamProvider.autoDispose<Map<String, double>>((ref)
final info = ref.watch(durationInfo.future);
return info.asStream();
);
【讨论】:
【参考方案2】:这个答案是@AlexHartford 所做的另一种方法。
我的案例目前的解决方案是使用包rxdartCombineLatestStream.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
使用的时候,我要知道返回结果的顺序。
【讨论】:
以上是关于Flutter Riverpod:使用 StreamProvider 返回 2 个流的主要内容,如果未能解决你的问题,请参考以下文章
使用新的 Flutter 2.2.2 版本为 Riverpod 运行“flutter pub get”时版本解决失败