写点什么

了解 Flutter 的 Timer 类和 Timer.periodic【Flutter 专题 19】

作者:坚果前端
  • 2021 年 12 月 09 日
  • 本文字数:4815 字

    阅读完需:约 16 分钟

了解 Flutter 的Timer类和Timer.periodic【Flutter专题19】

在构建移动应用程序时,我们经常会遇到必须在一定时间后执行任务的场景。还记得在进入应用程序之前看到闪亮的启动画面吗?

或者我们可能需要一段代码在一段时间后重复执行,比如显示剩余时间限制以填充一次性密码或每秒更改小部件的颜色以创建漂亮的动画。


为了解决 Flutter 应用程序中的这些需求,我们创建了这个Timer类。因此,在本文中,我们将介绍以下几点,以最好地了解如何将这些功能实现到您自己的 Flutter 应用程序中:


  • 什么是Timer类以及我们如何使用它

  • 如何创建一个定期计时器 timer.periodic

  • 如何创建可重启的计时器

  • 使用Timer类的例子


有了这个,让我们开始吧!

什么是Timer类?

Flutter 的Timer类允许我们创建一个倒数计时器。它在其生命周期中分别经历以下状态:


  • 创建一个计时器

  • 执行回调

  • 计时器结束


要使用属于 Dart 异步库一部分的 Timer 类,我们可以使用以下 import 语句导入它:


import 'dart:async';
复制代码

创建一个简单的计时器

现在,要创建一个简单的 3 秒计时器,请添加以下内容,它会在执行后触发回调:


final timer = Timer(  const Duration(seconds: 3),  () {    //做你想做的  },);
复制代码


例如,一旦回调触发,我们就可以让用户做你想做的。但是请注意,回调仅触发一次。

创建一个简单的周期性计时器

使用Timer.periodic,我们可以创建一个在给定持续时间后执行的重复计时器。定期计时器保持活动状态,直到它们被手动取消。Flutter 有一个名为 periodic 的不同工厂方法来创建这样的计时器。


周期性计时器的一个很好的例子是显示时间敏感操作的剩余时间,例如在 10 分钟内完成付款。在以下示例中,代码生成一个计时器,每秒触发一次回调:


final periodicTimer = Timer.periodic(  const Duration(seconds: 1),  (timer) {    // Update user about remaining time  },);
复制代码


请注意,默认情况下,周期性计时器无限期保持活动状态。


很简单,不是吗?是的,但是在实际用例中使用它时,我们还必须回答其他问题:


  • 如何取消活动计时器

  • 如何知道计时器是否仍然处于活动状态

  • 如何知道经过的持续时间

如何使用Timer

Timer班给了我们很多的其他选项可以轻松地使用它。让我们深入了解如何使用这些其他选项以及它们如何与普通和定期计时器一起工作。

如何取消活动计时器

所述Timer类具有cancel()抵消任何活动定时器的方法。对于普通计时器,调用cancel不会调用回调。对于周期定时器,cancel方法变得非常重要,因为我们必须完成定时器:


final periodicTimer = Timer.periodic(  const Duration(seconds: 1),  (timer) {    // Update user about remaining time  },);
final shouldStop = true; //No more tick-tock now! Please
if (shouldStop) { timer.cancel();}
复制代码


请注意,我们可以cancel根据需要调用任意多次而不会产生任何副作用;进一步的调用将被忽略。

如何知道计时器是否仍处于活动状态

active 如果回调没有触发并且我们没有明确取消它,则会调用普通计时器。


另一方面,如果我们没有特别取消它们,周期性计时器总是处于活动状态:


final timer = Timer(  const Duration(seconds: 3),  () {    // Navigate to your favorite place  },);
if (timer.isActive) { //}
复制代码

如何知道时间过去了

创建一个持续时间为 1 秒的定期计时器将在一分钟内滴答 60 次。虽然我们知道这本质上是正确的,但我们如何才能确切地知道计数?


这就是 tick 进来的地方。一个 tick 值从零开始,每次发生计时器事件时都会增加;此值是反映通过的持续时间数的计数。


例如,持续时间为 10 秒的周期性计时器将在一分钟内有六个事件,atick 将给出相对于当前时间点的值。也就是说,半分钟后,该 tick 值将 3 在每个事件上继续递增:


final periodicTimer = Timer.periodic(  const Duration(seconds: 10),  (timer) {    // Update user about remaining time  },);
final howMuchTimeBuddy = periodicTimer.tick;
复制代码


在上面的代码中,我们创建了一个持续时间为 10 秒的周期性计时器。我们可以获取任何给定时间点的 tick 值 periodicTimer.tick。

如何安排回调

Timer 该类还有一个更有趣的用例。使用 Timer,我们可以安排在异步模式下尽快执行的回调。为此,只需启动一个带有 zero 持续时间的计时器:


final zeroDurationTimer = Timer(  Duration.zero,  () {    //Execute this callback ASAP but asynchronously  },);
复制代码


还有一个方便的方法,相当于上面的代码,但更简洁:


final zeroDurationTimer = Timer.run(() {  //Execute this callback ASAP but asynchronously});
复制代码

在 Flutter 中创建可重启的计时器

正如我们在上面看到的,我们可以 Timer 通过调用该 cancel()方法来取消。但是,Timer 除非我们重新创建计时器实例,否则类中没有直接的方法来重新启动相同的计时器。


为了实现这一点,Flutter 具有 RestartableTimer. 这个可重启定时器的底层实现与创建定时器实例相同。因为 Timer 是一个抽象类,所以 RestartableTimer 是它的具体实现之一。


RestartableTimer 是包含实用程序类的 async 包的一部分 dart:async。它已经是 Flutter SDK 的一部分,可以通过以下方式导入:


import 'package:async/async.dart';
复制代码


导入后,我们可以创建一个简单的 3 秒 RestartableTimer:


final restartableTimer = RestartableTimer(  const Duration(seconds: 3),  () {    //Callback  },);
//Restart the timerrestartableTimer.reset();
复制代码


重要的是要注意,重置计时器会从其原始持续时间重新创建计时器。RestartableTimer 仅用于非周期性定时器。

FlutterTimer 示例和用例

在导航离开之前创建特定持续时间的屏幕

在开发应用程序时,我们必须经常创建一个在一段时间内保持活动状态的屏幕,然后继续应用程序的流程。这可能是启动画面、“您的订单已下单”屏幕或任何其他过渡元素。


在这个例子中,我们有第一个屏幕,RelaxingScreen,它将对用户可见 3 秒,并 NextScreen 在时间结束时导航到。


使用时 Timer,重要的是在处置时取消。这保证了当从树中删除相应的小部件时没有计时器保持活动状态。


看看下面的代码以使用 Timer 该类实现相同的目的:


import 'dart:async';
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() { runApp(MyApp());}
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark().copyWith( scaffoldBackgroundColor: darkBlue, ), debugShowCheckedModeBanner: false, home: const Scaffold( body: Center( child: RelaxingScreen(), ), ), ); }}
/// Releaxing screen that stays visible for 3 secondsclass RelaxingScreen extends StatefulWidget { const RelaxingScreen({Key? key}) : super(key: key);
@override _RelaxingScreenState createState() => _RelaxingScreenState();}
class _RelaxingScreenState extends State<RelaxingScreen> { //Declare a timer Timer? timer;

@override void initState() { super.initState();
/// Initialize timer for 3 seconds, it will be active as soon as intialized timer = Timer( const Duration(seconds: 3), () { /// Navigate to seconds screen when timer callback in executed Navigator.push( context, MaterialPageRoute( builder: (context) => const NextScreen(), ), ); }, ); }
/// cancel the timer when widget is disposed, /// to avoid any active timer that is not executed yet @override void dispose() { super.dispose(); timer?.cancel(); }
@override Widget build(BuildContext context) { return const Text("Relaxing Screen!!"); }}
class NextScreen extends StatelessWidget { const NextScreen({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return const Scaffold( body: Center( child: Text("Next Screen"), ), ); }}
复制代码


在上面的例子中,我们首先 RelaxingScreen 对用户可见,这是一个有状态的小部件,然后我们必须在 initState() 注册 TIMER。


在 3 秒计时器后,将触发回调以将用户导航到 NextScreen。取消 dispose()方法上的计时器很重要,以避免在用户离开 RelaxingScreen 回调触发之前可能创建的任何异常。

自动将计数器应用程序增加 1 秒

作为 Flutter 开发人员,您很可能熟悉非常著名的计数器应用程序 😅。在这个例子中,我们将创建一个类似的计数器应用程序,但不是按 + 按钮,我们将每 1 秒自动增加计数器并通过重建 Text 小部件将其显示给用户:


import 'dart:async';
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() { runApp(MyApp());}
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark().copyWith( scaffoldBackgroundColor: darkBlue, ), debugShowCheckedModeBanner: false, home: const Scaffold( body: Center( child: CounterScreen(), ), ), ); }}
class CounterScreen extends StatefulWidget { const CounterScreen({Key key}) : super(key: key);
@override _CounterScreenState createState() => _CounterScreenState();}
class _CounterScreenState extends State<CounterScreen> { /// declare a cound variable with initial value int count = 0;
/// declare a timer Timer timer;
@override void initState() { super.initState();
/// Initialize a periodic timer with 1 second duration timer = Timer.periodic( const Duration(seconds: 1), (timer) { /// callback will be executed every 1 second, increament a count value /// on each callback setState(() { count++; }); }, ); }
/// Since periodic timer doesn't cancels untill expicitely called /// It is important to cancel them on dispose, so that it doesn't stays active /// when widget is not binded to tree @override void dispose() { super.dispose(); timer?.cancel(); }
@override Widget build(BuildContext context) { return Text("Counter reached $count"); }}
复制代码


在上面的例子中,有一个 StatefulWidget, CounterScreen,我们注册了一个周期性的计时器,每 1 秒滴答一次。在每次触发回调时,我们都会增加状态变量 count。然后 Text 小部件显示 的最新值 count。


也可以采用类似的方法来显示倒数计时器或剩余持续时间(例如,一次性密码超时)。

FlutterTimer 类的局限性

当我们想到通用计时器时,通常会期望诸如暂停或恢复计时器之类的实用程序。到目前为止,我们已经看到,Flutter 的 Timer 类旨在为以后安排一个代码块或在特定持续时间内重复执行它。


要在 Flutter 中实现诸如暂停和恢复计时器之 Stopwatch 类的实用程序,您可以使用类.

总结

Flutter 的 Timer 类处理与倒数计时器相关的每个用例。有了它,我们可以创建一个具有完整实用程序的普通和定期计时器,例如取消计时器、识别计时器是否处于活动状态以及滴答计数。


我们还看到了如何使用 RestartableTimer 可以重置和再次启动计时器。


感谢您的阅读,不要忘记分享您在我这儿学习到的知识,我是坚果。

发布于: 19 小时前阅读数: 21
用户头像

坚果前端

关注

此间若无火炬,我便是唯一的光 2020.10.25 加入

公众号:“坚果前端”,华为云享专家,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。

评论

发布
暂无评论
了解 Flutter 的Timer类和Timer.periodic【Flutter专题19】