在Flutter开发中,定时任务是常见的需求场景,如轮询请求、倒计时、延迟执行等。本文将全面介绍Flutter中实现定时任务的8种方法,并附上详细代码示例和最佳实践。

📋 目录

  1. Timer类 - 最基础的定时器
  2. Future.delayed - 简单的延迟执行
  3. Stream.periodic - 响应式定时流
  4. AnimationController - 动画定时器
  5. Ticker - 帧同步定时器
  6. WorkManager - 后台定时任务
  7. cron - 复杂定时表达式
  8. 完整实战案例
  9. 性能优化与注意事项

  1. Timer类 - 最基础的定时器

1.1 基本用法

import 'dart:async';

/// 一次性定时器:3秒后执行
Timer(Duration(seconds: 3), () {
  print('3秒后执行的代码');
});

/// 周期性定时器:每秒执行一次
Timer.periodic(Duration(seconds: 1), (timer) {
  print('第${timer.tick}次执行'); // tick属性记录执行次数
  
  // 执行5次后取消定时器
  if (timer.tick >= 5) {
    timer.cancel();
    print('定时器已取消');
  }
});

1.2 在StatefulWidget中的完整示例

import 'dart:async';
import 'package:flutter/material.dart';

class TimerExample extends StatefulWidget {
  
  _TimerExampleState createState() => _TimerExampleState();
}

class _TimerExampleState extends State<TimerExample> {
  Timer? _timer;           // 定时器实例
  int _counter = 0;        // 计数器
  bool _isRunning = false; // 定时器运行状态

  
  void initState() {
    super.initState();
    // 页面加载后延迟2秒开始计时
    Future.delayed(Duration(seconds: 2), _startTimer);
  }

  /// 启动定时器
  void _startTimer() {
    setState(() {
      _isRunning = true;
      _counter = 0;
    });
    
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _counter++;
      });
      
      // 10秒后自动停止
      if (_counter >= 10) {
        _stopTimer();
      }
    });
  }

  /// 停止定时器
  void _stopTimer() {
    _timer?.cancel();
    setState(() {
      _isRunning = false;
    });
  }

  /// 暂停/继续定时器
  void _toggleTimer() {
    if (_isRunning) {
      _stopTimer();
    } else {
      _startTimer();
    }
  }

  
  void dispose() {
    /// ⚠️ 重要:组件销毁时必须取消定时器,防止内存泄漏
    _timer?.cancel();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Timer示例')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            /// 显示计时结果
            Text('计时: $_counter 秒',
              style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold)),
            SizedBox(height: 30),
            
            /// 控制按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: _toggleTimer,
                  child: Text(_isRunning ? '暂停' : '继续'),
                ),
                SizedBox(width: 20),
                ElevatedButton(
                  onPressed: _startTimer,
                  child: Text('重置'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

  1. Future.delayed - 简单的延迟执行
/// 基本延迟执行
Future.delayed(Duration(seconds: 2), () {
  print('延迟2秒后执行');
});

/// 链式延迟执行 - 模拟多个延迟任务
Future<void> chainDelayedExample() async {
  print('任务开始');
  
  await Future.delayed(Duration(seconds: 1));
  print('1秒后执行第一个任务');
  
  await Future.delayed(Duration(milliseconds: 500));
  print('0.5秒后执行第二个任务');
  
  await Future.delayed(Duration(seconds: 2));
  print('2秒后执行第三个任务');
  
  print('所有延迟任务完成');
}

/// 在build方法中延迟更新UI
Future<void> delayedBuildUpdate() async {
  // 等待数据加载
  await Future.delayed(Duration(seconds: 3));
  
  // 注意:这里需要检查mounted,防止组件已销毁
  if (mounted) {
    setState(() {
      // 更新UI状态
    });
  }
}

  1. Stream.periodic - 响应式定时流

3.1 基本用法

import 'dart:async';

/// 创建每秒发射一个事件的流
final Stream<int> numberStream = Stream<int>.periodic(
  Duration(seconds: 1),      // 时间间隔
  (count) => count + 1,      // 每次发射的值
).take(10);                  // 只取前10个值

// 监听流
numberStream.listen((number) {
  print('收到数字: $number');
}, onDone: () {
  print('流已完成');
});

3.2 结合StreamBuilder构建响应式UI

import 'package:flutter/material.dart';

class StreamTimerExample extends StatelessWidget {
  /// 创建倒计时流:从60秒到0秒
  final Stream<int> countdownStream = Stream<int>.periodic(
    Duration(seconds: 1),
    (x) => 60 - x - 1,
  ).takeWhile((x) => x >= 0); // 条件过滤

  
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: countdownStream,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Text('准备开始...');
        }
        
        if (snapshot.hasError) {
          return Text('错误: ${snapshot.error}');
        }
        
        final seconds = snapshot.data ?? 0;
        
        return Column(
          children: [
            // 倒计时显示
            Text('$seconds',
              style: TextStyle(
                fontSize: 72,
                color: seconds < 10 ? Colors.red : Colors.black,
              )),
            
            // 进度条
            LinearProgressIndicator(
              value: seconds / 60,
            ),
            
            // 状态文本
            Text(
              seconds > 0 ? '倒计时中...' : '时间到!',
              style: TextStyle(
                fontSize: 24,
                color: seconds > 0 ? Colors.grey : Colors.green,
              ),
            ),
          ],
        );
      },
    );
  }
}

  1. AnimationController - 动画定时器
import 'package:flutter/material.dart';

class AnimationTimerExample extends StatefulWidget {
  
  _AnimationTimerExampleState createState() => _AnimationTimerExampleState();
}

class _AnimationTimerExampleState extends State<AnimationTimerExample> 
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  
  
  void initState() {
    super.initState();
    
    /// 创建动画控制器,持续10秒
    _controller = AnimationController(
      duration: Duration(seconds: 10),
      vsync: this,  // 提供TickerProvider
    );
    
    /// 创建动画曲线
    _animation = CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    );
    
    /// 添加状态监听器
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        print('动画完成');
      } else if (status == AnimationStatus.dismissed) {
        print('动画重置');
      }
    });
    
    /// 开始正向动画
    _controller.forward();
  }
  
  /// 暂停动画
  void _pauseAnimation() {
    _controller.stop();
  }
  
  /// 继续动画
  void _resumeAnimation() {
    _controller.forward();
  }
  
  /// 重置动画
  void _resetAnimation() {
    _controller.reset();
    _controller.forward();
  }
  
  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Column(
          children: [
            // 进度条
            LinearProgressIndicator(value: _animation.value),
            
            // 旋转的加载图标
            Transform.rotate(
              angle: _animation.value * 2 * 3.14159, // 完整旋转
              child: Icon(Icons.refresh, size: 50),
            ),
            
            // 文本显示进度百分比
            Text('进度: ${(_animation.value * 100).toStringAsFixed(1)}%'),
          ],
        );
      },
    );
  }
}

  1. Ticker - 帧同步定时器
import 'package:flutter/scheduler.dart';

class TickerExample extends StatefulWidget {
  
  _TickerExampleState createState() => _TickerExampleState();
}

class _TickerExampleState extends State<TickerExample> 
    with SingleTickerProviderStateMixin {
  late Ticker _ticker;
  int _frameCount = 0;
  DateTime? _startTime;
  double? _fps;
  
  
  void initState() {
    super.initState();
    
    /// 创建Ticker,每帧都会回调
    _ticker = createTicker((elapsed) {
      _frameCount++;
      
      // 计算FPS
      if (_startTime == null) {
        _startTime = DateTime.now();
      } else {
        final duration = DateTime.now().difference(_startTime!);
        if (duration.inMilliseconds > 0) {
          _fps = _frameCount / (duration.inMilliseconds / 1000);
        }
      }
      
      if (mounted) {
        setState(() {});
      }
    });
    
    _ticker.start();
  }
  
  
  void dispose() {
    /// 停止并销毁Ticker
    _ticker.stop();
    _ticker.dispose();
    super.dispose();
  }
  
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('帧数: $_frameCount'),
        if (_fps != null) Text('FPS: ${_fps!.toStringAsFixed(1)}'),
        
        // 一个简单的动画演示
        Container(
          width: 100 + (_frameCount % 100).toDouble(),
          height: 100,
          color: Colors.blue,
          alignment: Alignment.center,
          child: Text('${_frameCount % 100}'),
        ),
      ],
    );
  }
}

  1. WorkManager - 后台定时任务

6.1 添加依赖

# pubspec.yaml
dependencies:
  workmanager: ^0.5.0
  flutter_local_notifications: ^9.0.0

6.2 后台任务实现

import 'package:workmanager/workmanager.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

/// 初始化WorkManager
void initWorkManager() {
  Workmanager().initialize(
    callbackDispatcher,     // 后台任务回调
    isInDebugMode: true,   // 调试模式
  );
}

/// 后台任务回调函数
('vm:entry-point')  // 重要:保持函数可被后台调用
void callbackDispatcher() {
  Workmanager().executeTask((taskName, inputData) async {
    print("后台任务执行: $taskName");
    
    // 初始化通知插件
    final FlutterLocalNotificationsPlugin notificationsPlugin = 
        FlutterLocalNotificationsPlugin();
    
    // 显示通知
    await notificationsPlugin.show(
      0,
      '定时任务提醒',
      '任务 "$taskName" 已执行',
      NotificationDetails(
        android: AndroidNotificationDetails(
          'channel_id',
          '定时任务',
          importance: Importance.high,
        ),
        iOS: DarwinNotificationDetails(),
      ),
    );
    
    return Future.value(true); // 返回true表示任务成功
  });
}

/// 注册定时任务
void registerBackgroundTasks() {
  // 一次性任务:15分钟后执行
  Workmanager().registerOneOffTask(
    "taskOne",
    "simpleTask",
    initialDelay: Duration(minutes: 15),
    inputData: {"data": "一次性任务"},
  );
  
  // 周期性任务:每1小时执行
  Workmanager().registerPeriodicTask(
    "taskTwo",
    "simpleTask",
    frequency: Duration(hours: 1),
    constraints: Constraints(
      networkType: NetworkType.connected, // 需要网络
    ),
  );
  
  // 精确定时:每天上午10点执行
  Workmanager().registerPeriodicTask(
    "dailyTask",
    "simpleTask",
    frequency: Duration(hours: 24),
    initialDelay: _calculateInitialDelay(10, 0), // 计算到上午10点的延迟
  );
}

/// 计算到指定时间的延迟
Duration _calculateInitialDelay(int hour, int minute) {
  final now = DateTime.now();
  var scheduledTime = DateTime(now.year, now.month, now.day, hour, minute);
  
  if (scheduledTime.isBefore(now)) {
    scheduledTime = scheduledTime.add(Duration(days: 1));
  }
  
  return scheduledTime.difference(now);
}

  1. cron - 复杂定时表达式

7.1 添加依赖

dependencies:
  cron: ^0.4.0

7.2 使用cron表达式

import 'package:cron/cron.dart';

void cronExample() {
  final cron = Cron();
  
  /// 每5秒执行一次
  cron.schedule(
    Schedule.parse('*/5 * * * * *'), // cron表达式
    () async {
      print('每5秒执行: ${DateTime.now()}');
    },
  );
  
  /// 每分钟的第30秒执行
  cron.schedule(
    Schedule.parse('30 * * * * *'),
    () => print('每分钟30秒执行'),
  );
  
  /// 每天上午10:15执行
  cron.schedule(
    Schedule.parse('0 15 10 * * *'),
    () => print('每天10:15执行'),
  );
  
  /// 工作日(周一到周五)上午9点执行
  cron.schedule(
    Schedule.parse('0 0 9 * * 1-5'),
    () => print('工作日9点执行'),
  );
  
  /// 停止所有定时任务
  Future.delayed(Duration(minutes: 10), () {
    cron.close();
    print('所有cron任务已停止');
  });
}

  1. 完整实战案例:倒计时器
import 'package:flutter/material.dart';
import 'dart:async';

class CountdownTimerApp extends StatefulWidget {
  
  _CountdownTimerAppState createState() => _CountdownTimerAppState();
}

class _CountdownTimerAppState extends State<CountdownTimerApp> 
    with SingleTickerProviderStateMixin {
  // 定时器相关
  Timer? _timer;
  Duration _duration = Duration(seconds: 300); // 5分钟
  bool _isRunning = false;
  
  // 动画相关
  late AnimationController _animationController;
  late Animation<double> _animation;
  
  
  void initState() {
    super.initState();
    
    /// 初始化动画控制器
    _animationController = AnimationController(
      duration: _duration,
      vsync: this,
    )..addListener(() {
        if (mounted) setState(() {});
      });
    
    /// 创建动画
    _animation = Tween<double>(begin: 1.0, end: 0.0)
        .animate(_animationController);
  }
  
  /// 开始/暂停计时
  void _toggleTimer() {
    if (_isRunning) {
      _pauseTimer();
    } else {
      _startTimer();
    }
  }
  
  /// 启动计时器
  void _startTimer() {
    if (_duration.inSeconds <= 0) return;
    
    setState(() => _isRunning = true);
    
    /// 启动动画
    _animationController.duration = _duration;
    _animationController.forward(from: 1.0 - (_animation.value));
    
    /// 启动定时器
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {
        _duration = _duration - Duration(seconds: 1);
        
        // 时间到
        if (_duration.inSeconds <= 0) {
          _timerComplete();
        }
      });
    });
  }
  
  /// 暂停计时器
  void _pauseTimer() {
    setState(() => _isRunning = false);
    _timer?.cancel();
    _animationController.stop();
  }
  
  /// 重置计时器
  void _resetTimer() {
    _pauseTimer();
    setState(() {
      _duration = Duration(seconds: 300);
    });
    _animationController.reset();
  }
  
  /// 时间到处理
  void _timerComplete() {
    _pauseTimer();
    
    // 显示完成对话框
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('时间到!'),
        content: Text('5分钟倒计时结束'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text('确定'),
          ),
        ],
      ),
    );
  }
  
  /// 格式化时间显示
  String _formatDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final minutes = twoDigits(duration.inMinutes.remainder(60));
    final seconds = twoDigits(duration.inSeconds.remainder(60));
    return '$minutes:$seconds';
  }
  
  
  void dispose() {
    _timer?.cancel();
    _animationController.dispose();
    super.dispose();
  }
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('倒计时器'),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            /// 圆形进度指示器
            SizedBox(
              width: 200,
              height: 200,
              child: Stack(
                alignment: Alignment.center,
                children: [
                  // 背景圆
                  CircularProgressIndicator(
                    value: _animation.value,
                    strokeWidth: 10,
                    backgroundColor: Colors.grey[200],
                    valueColor: AlwaysStoppedAnimation(
                      _isRunning ? Colors.blue : Colors.grey,
                    ),
                  ),
                  
                  // 时间文本
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        _formatDuration(_duration),
                        style: TextStyle(
                          fontSize: 36,
                          fontWeight: FontWeight.bold,
                          color: _duration.inSeconds < 60 ? Colors.red : Colors.black,
                        ),
                      ),
                      SizedBox(height: 8),
                      Text(
                        _isRunning ? '倒计时中...' : '已暂停',
                        style: TextStyle(
                          fontSize: 14,
                          color: Colors.grey,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
            
            SizedBox(height: 40),
            
            /// 控制按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                FloatingActionButton(
                  onPressed: _toggleTimer,
                  child: Icon(_isRunning ? Icons.pause : Icons.play_arrow),
                  backgroundColor: _isRunning ? Colors.orange : Colors.green,
                ),
                
                SizedBox(width: 20),
                
                FloatingActionButton(
                  onPressed: _resetTimer,
                  child: Icon(Icons.replay),
                  backgroundColor: Colors.blue,
                ),
              ],
            ),
            
            SizedBox(height: 20),
            
            /// 时间调节按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                _buildTimeAdjustButton('-1分', Duration(minutes: -1)),
                SizedBox(width: 10),
                _buildTimeAdjustButton('+1分', Duration(minutes: 1)),
                SizedBox(width: 10),
                _buildTimeAdjustButton('-5分', Duration(minutes: -5)),
                SizedBox(width: 10),
                _buildTimeAdjustButton('+5分', Duration(minutes: 5)),
              ],
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildTimeAdjustButton(String label, Duration adjustment) {
    return ElevatedButton(
      onPressed: _isRunning ? null : () {
        setState(() {
          final newDuration = _duration + adjustment;
          if (newDuration.inSeconds > 0) {
            _duration = newDuration;
          }
        });
      },
      child: Text(label),
    );
  }
}

  1. 性能优化与注意事项

9.1 内存管理最佳实践

/// 1. 始终在dispose中取消定时器

void dispose() {
  _timer?.cancel();  // ✅ 正确做法
  super.dispose();   // 注意顺序
}

/// 2. 使用计时器前检查mounted状态
void _safeTimerCallback() {
  if (!mounted) return;  // 防止组件销毁后调用setState
  
  setState(() {
    // 更新UI
  });
}

/// 3. 避免在build方法中创建定时器
// ❌ 错误做法 - 每次build都会创建新定时器
Widget build(BuildContext context) {
  Timer(Duration(seconds: 1), () {}); // 错误!
  return Container();
}

// ✅ 正确做法 - 在initState或回调方法中创建

void initState() {
  super.initState();
  _startTimer();  // 正确
}

9.2 性能优化建议

/// 1. 使用ValueNotifier减少setState调用
class OptimizedTimerExample extends StatefulWidget {
  
  _OptimizedTimerExampleState createState() => _OptimizedTimerExampleState();
}

class _OptimizedTimerExampleState extends State<OptimizedTimerExample> {
  final ValueNotifier<int> _counter = ValueNotifier<int>(0);
  Timer? _timer;
  
  
  void initState() {
    super.initState();
    
    // 使用ValueNotifier更新,避免整个widget重建
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      _counter.value++;  // 只重建依赖的部分
    });
  }
  
  
  Widget build(BuildContext context) {
    return ValueListenableBuilder<int>(
      valueListenable: _counter,
      builder: (context, value, child) {
        return Text('计数: $value');  // 只有这部分会重建
      },
    );
  }
}

/// 2. 对于频繁更新,考虑使用Ticker或AnimationController
/// 它们与屏幕刷新率同步,性能更好

9.3 常见问题与解决方案

问题 原因 解决方案
定时器不精确 Dart事件循环延迟 使用Ticker或AnimationController
后台定时器不工作 系统限制 使用WorkManager插件
内存泄漏 未及时取消定时器 确保在dispose()中cancel()
UI卡顿 频繁调用setState 使用ValueNotifier或StreamBuilder
定时器在页面切换后仍运行 未处理页面生命周期 在deactivate中暂停,在activate中恢复

9.4 平台差异注意事项

/// iOS后台限制处理
void handleIOSBackground() {
  // iOS后台最多执行10分钟
  // 需要配置后台模式:Audio、Location、VoIP等
  // 考虑使用推送通知替代定时任务
}

/// Android前台服务
void setupAndroidForegroundService() {
  // Android 8.0+需要前台服务
  // 使用flutter_foreground_task插件
  // 显示持续通知
}

/// 省电模式处理
void handleBatteryOptimization() {
  // 检查是否在省电白名单中
  // 引导用户关闭省电限制
  // 减少定时频率或使用WorkManager
}

📚 总结

Flutter提供了多种定时任务实现方式,各有适用场景:

· 简单延迟:使用Future.delayed
· 基础定时:使用Timer或Timer.periodic
· 响应式UI:使用Stream.periodic + StreamBuilder
· 动画相关:使用AnimationController
· 帧同步:使用Ticker
· 后台任务:使用WorkManager插件
· 复杂调度:使用cron插件

选择合适的方式,并遵循最佳实践,可以创建出高效、稳定的定时功能。记住关键原则:及时清理资源、考虑平台差异、优化性能表现。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐