开发者社区> 大前端之旅> 正文

了解 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 timer
restartableTimer.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 seconds
class 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 可以重置和再次启动计时器。


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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
9832 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
13693 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
20532 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
33455 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18805 0
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
35211 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
25145 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
11850 0
+关注
大前端之旅
公众号大前端之旅
349
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载