首页 > 解决方案 > 如何处理 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”)?或者有没有更好的方法来处理这个特定的任务?

标签: darttimerstreamcancellation

解决方案


你很接近,你只需要在计时器倒计时时播放歌曲,同时取消计时器。所以:

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。)

使用这种编写方式,取消计时器会阻止您播放歌曲。


推荐阅读