dart - 如何处理 Timer.periodic 或 Stream.periodic 的“onCancel”
问题描述
每当用户想要播放一些音频时,首先我想等待 5 秒,然后每隔一秒执行一个动作。每当用户按下播放按钮时,我都会调用onPlay()
方法。我的第一次尝试是这样的:
Timer? _timer; // I might need to cancel timer also when the user pauses playback by pause button or something
void onPlay() async {
int _secondsLeft = 5;
_timer = await Timer.periodic(const Duration(seconds: 1), (_) {
if (_secondsLeft == 0) _timer?.cancel();
_textToSpeech.speak(_secondsLeft.toString());
--_secondsLeft;
});
audio.play(_curSong);
}
此尝试无法正常工作,因为audio.play()
在 Timer 初始化后立即运行,未完成。我发现了如何使 Timer.periodic 在达到条件时自行取消?并使用其中一个答案来改进我的代码,如下所示:
StreamSubscription? _timer;
void onPlay() async {
int _secondsLeft = 5;
_timer = await Stream.periodic(const Duration(seconds: 1))
.takeWhile((_) => _secondsLeft > 0)
.forEach((_) {
_textToSpeech.speak(_secondsLeft.toString());
--_secondsLeft;
});
audio.play(_curSong);
}
这效果更好,但如果用户在初始阶段切换到不同的歌曲或暂停播放,_timer?.cancel()
只会取消流,因此它之后的所有内容 ( audio.play(_curSong)
) 仍在运行。但我不仅想取消流,还想跳过该audio.play()
功能。所以我想audio.play()
只在定时器/流正确完成而不取消后运行。
是否有任何选项来处理 Stream.periodic 或 Timer.periodic 取消操作(“onCancel”)?或者有没有更好的方法来处理这个特定的任务?
解决方案
你很接近,你只需要在计时器倒计时时播放歌曲,同时取消计时器。所以:
Timer? _timer;
void onPlay() async {
int _secondsLeft = 5;
_timer = await Timer.periodic(const Duration(seconds: 1), (_) {
if (_secondsLeft == 0) {
_timer?.cancel();
audio.play(_curSong);
} else {
_textToSpeech.speak(_secondsLeft.toString());
--_secondsLeft;
}
});
}
(请注意,这并没有说zero
,您原来的位置。而是播放音乐。如果您希望它说零,请将 更改== 0
为< 0
。)
使用这种编写方式,取消计时器会阻止您播放歌曲。
推荐阅读
- java - 如何从毕加索导入图像
- swagger - 执行swagger代码生成失败
- sql-server - 优化 SQL Server 性能(大量等待任务)
- wpf - WPF ValidationRule 和 DataTrigger 禁用提交按钮
- python - 如何在python中使用if else语句对变量进行bin
- c# - 当从 C# 代码插入 dateTime 对象到 Sql Server 数据库时,语法格式发生了变化
- r - scale_x_discrete 的轴标签不正确
- laravel - 在 int 上调用成员函数 save()
- javascript - React - 如何访问自动完成的结果
- php - Laravel PasswordBroker::createToken() 必须实现接口