[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();
相关推荐
AiFlutter3 小时前
Flutter之Package教程
flutter
Mingyueyixi7 小时前
Flutter Spacer引发的The ParentDataWidget Expanded(flex: 1) 惨案
前端·flutter
crasowas16 小时前
Flutter问题记录 - 适配Xcode 16和iOS 18
flutter·ios·xcode
老田低代码2 天前
Dart自从引入null check后写Flutter App总有一种难受的感觉
前端·flutter
AiFlutter2 天前
Flutter Web首次加载时添加动画
前端·flutter
ZemanZhang3 天前
Flutter启动无法运行热重载
flutter
AiFlutter4 天前
Flutter-底部选择弹窗(showModalBottomSheet)
flutter
帅次4 天前
Android Studio:驱动高效开发的全方位智能平台
android·ide·flutter·kotlin·gradle·android studio·android jetpack
程序者王大川4 天前
【前端】Flutter vs uni-app:性能对比分析
前端·flutter·uni-app·安卓·全栈·性能分析·原生
yang2952423614 天前
使用 Vue.js 将数据对象的值放入另一个数据对象中
前端·vue.js·flutter