[Flutter]倒计时和计时器

1.延迟执行

Future.delayed

使用Future.delayed可以在延迟一定时间后执行代码。这是实现延迟执行最简单的方式之一。

Dart 复制代码
Future.delayed(Duration(seconds: 1), () {
  // 这里的代码会在1秒后执行
  print('This message is displayed after 1 second.');
});

Timer

Timer类提供了更灵活的方式来实现单次或重复的延迟执行。

Dart 复制代码
// 单次延迟
Timer(Duration(seconds: 1), () {
  // 这里的代码会在1秒后执行
  print('This message is displayed after 1 second.');
});

// 重复执行
Timer.periodic(Duration(seconds: 1), (Timer t) {
  // 这里的代码会每1秒执行一次
  print('This message is displayed every 1 second.');
});

AnimationController

在动画中,使用AnimationController可以在动画帧更新时执行代码,这可以用来实现延迟。

Dart 复制代码
AnimationController controller = AnimationController(
  duration: Duration(seconds: 1),
  vsync: this, // 需要一个TickerProvider类型的vsync参数
);

controller.forward().then((_) {
  // 这里的代码会在动画结束后执行
  print('This message is displayed after the animation ends.');
});

Future

如果你已经在处理Future,也可以通过.then()链式调用在Future完成后延迟执行代码。

Dart 复制代码
someFuture().then((value) {
  // 做一些处理...
}).then((_) {
  // 这里的代码会紧接着前一个then执行后执行
  print('This message is displayed after the future completes.');
});

使用async和await

结合使用asyncawait关键字,可以让你在异步函数中顺序执行代码块,看起来像是同步代码。

Dart 复制代码
Future<void> delayedPrint() async {
  await Future.delayed(Duration(seconds: 1));
  print('This message is displayed after 1 second.');
}

delayedPrint();

进一步封装一下

Dart 复制代码
class Tools {
  // 延迟执行
  static void delayExecution(int second, void Function() callback) async {
    await Future.delayed(Duration(seconds: second));
    callback();
  }
}

Tools.delayExecution(3, () {
    print("execute");
});

Isolates

当需要执行长时间运行的计算任务时,可以使用Isolates来实现不阻塞主线程的延迟执行。这在Flutter中用于并行计算或执行耗时任务。

Dart 复制代码
import 'dart:isolate';

void longRunningTask(SendPort sendPort) {
  // 执行耗时任务
  sendPort.send(result);
}

void startIsolate() async {
  ReceivePort receivePort = ReceivePort();
  Isolate.spawn(longRunningTask, receivePort.sendPort);

  receivePort.listen((data) {
    // 获取到结果后执行的操作
  });
}

在实际应用中,选择哪种方式取决于你的具体需求。对于简单的延迟执行,通常Future.delayedTimer就足够使用。而对于涉及动画或者复杂异步流程的情况,则可能需要使用AnimationController或者结合asyncawait的方式。对于需要后台执行的长时间运行任务,则可能需要使用Isolate

2.全局控制的倒计时

要创建一个全局定时器,可以通过单例模式封装一个定时器管理类。这个类可以提供启动、暂停、重启和关闭定时器的方法,并且确保定时完成后自动释放定时器资源。

以下是一个简单的全局定时器管理类示例:

Dart 复制代码
import 'dart:async';

class GlobalTimer {
  static final GlobalTimer _instance = GlobalTimer._internal();
  Timer? _timer;

  factory GlobalTimer() {
    return _instance;
  }

  GlobalTimer._internal();

  void startTimer({
    required Duration delay,
    required VoidCallback action,
  }) {
    _timer?.cancel(); // 取消之前的计时器(如果存在)
    _timer = Timer(delay, () {
      action();
      // 计时器执行完成后释放资源
      _timer?.cancel();
      _timer = null;
    });
  }

  void pauseTimer() {
    if (_timer?.isActive ?? false) {
      _timer?.cancel();
    }
  }

  void resumeTimer({
    required Duration delay,
    required VoidCallback action,
  }) {
    pauseTimer(); // 先暂停计时器
    startTimer(delay: delay, action: action); // 重新开始计时器
  }

  void stopTimer() {
    _timer?.cancel();
    _timer = null;
  }

  bool isTimerActive() {
    return _timer?.isActive ?? false;
  }
}

使用:

Dart 复制代码
// 启动定时器
GlobalTimer().startTimer(
  delay: Duration(seconds: 5),
  action: () {
    print('Timer action executed after 5 seconds');
  },
);

// 暂停定时器
GlobalTimer().pauseTimer();

// 重启定时器
GlobalTimer().resumeTimer(
  delay: Duration(seconds: 5),
  action: () {
    print('Timer action executed after another 5 seconds');
  },
);

// 停止定时器
GlobalTimer().stopTimer();

// 检查定时器是否活跃
bool isActive = GlobalTimer().isTimerActive();

这个类使用了单例模式,确保全局只有一个GlobalTimer实例。startTimer方法用于设置定时器,接收延迟时间和要执行的动作。pauseTimer会暂停定时器,resumeTimer可以重启定时器,而stopTimer会停止定时器并释放资源。isTimerActive方法用于检查定时器是否在运行中。

这个类不是线程安全的,因为Dart本身是单线程的,但是如果你使用它在Flutter的Isolates(类似于线程)中,请确保你正确地管理状态。此外,如果你的应用需要更复杂的定时器调度,你可能需要考虑其他的包或者解决方案。

3.全局控制的计时器

要创建一个全局可控的计时器,你可以使用单例模式并结合StreamStreamController来实现计时器状态的全局订阅。这样,你可以在任何地方订阅计时器的变化,并实现回调更新。

以下是一个实现全局计时器的示例:

Dart 复制代码
import 'dart:async';

class GlobalTimer {
  static final GlobalTimer _instance = GlobalTimer._internal();
  Timer? _timer;
  int _elapsedSeconds = 0;
  final StreamController<int> _streamController = StreamController<int>.broadcast();

  DateTime? _startTime;

  factory GlobalTimer() {
    return _instance;
  }

  GlobalTimer._internal();

  void startTimer() {
    if (_timer != null && _timer!.isActive) {
      // 如果计时器已经启动,则不做任何操作
      return;
    }
    _startTime = DateTime.now(); // 记录开始计时的时间戳
    _timer = Timer.periodic(Duration(seconds: 1), (Timer timer) {
      _elapsedSeconds++;
      _streamController.add(_elapsedSeconds); // 通过Stream通知订阅者
    });
  }

  void stopTimer() {
    _timer?.cancel();
    _timer = null;
    _elapsedSeconds = 0; // 重置累计时间
    _startTime = null;
  }

  int get elapsedSeconds => _elapsedSeconds;

  Stream<int> get timerStream => _streamController.stream;

  static String formatDuration(int totalSeconds) {
    int hours = totalSeconds ~/ 3600;
    int minutes = (totalSeconds % 3600) ~/ 60;
    int seconds = totalSeconds % 60;

    String hoursStr = (hours).toString().padLeft(2, '0');
    String minutesStr = (minutes).toString().padLeft(2, '0');
    String secondsStr = (seconds).toString().padLeft(2, '0');

    return "$hoursStr:$minutesStr:$secondsStr";
  }

  void dispose() {
    _streamController.close();
  }
}

使用:

Dart 复制代码
// 启动计时器
GlobalTimer().startTimer();

// 停止计时器
GlobalTimer().stopTimer();

// 获取当前累计计时时长
int seconds = GlobalTimer().elapsedSeconds;

// 格式化计时显示
String formattedTime = GlobalTimer.formatDuration(seconds);

// 订阅计时变化
GlobalTimer().timerStream.listen((int elapsedSeconds) {
  print('Timer updated: $elapsedSeconds seconds');
  // 更新页面等...
});

// 释放资源
GlobalTimer().dispose();
相关推荐
火柴就是我10 小时前
flutter 之真手势冲突处理
android·flutter
Speed12310 小时前
`mockito` 的核心“打桩”规则
flutter·dart
法的空间10 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
恋猫de小郭11 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone11 小时前
从flutter源码看其渲染机制
android·flutter
ALLIN1 天前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei1 天前
Flutter 国际化
flutter
Dabei1 天前
Flutter MQTT 通信文档
flutter
Dabei1 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉1 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter