Flutter中如何将计时器保存至本地内存?
实现Flutter后台持续计时并重启恢复的方案
你之前用SharedPreferences失败的核心原因是直接存储剩余时间——应用退到后台后,计时器会暂停,存储的剩余时间不会随系统时间自动减少,重启后显示的就不是真实剩余时长。正确的思路是存储计时器的结束时间戳,利用系统时间的持续流逝来计算剩余时间。
核心逻辑
- 点击开始计时时,计算出「当前时间 + 总计时时长」的结束时间戳(毫秒级),将这个值存在SharedPreferences里。
- 重启应用时,读取存储的结束时间戳,和当前系统时间对比:
- 如果当前时间已超过结束时间,说明计时完成,重置状态。
- 如果未超过,用「结束时间 - 当前时间」算出真实剩余时长,再启动计时器刷新UI。
代码实现示例
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:async'; import 'dart:math'; class PersistentTimerPage extends StatefulWidget { const PersistentTimerPage({super.key}); @override State<PersistentTimerPage> createState() => _PersistentTimerPageState(); } class _PersistentTimerPageState extends State<PersistentTimerPage> { late SharedPreferences _prefs; int? _endTimeMillis; // 存储的结束时间戳(毫秒) int _remainingSeconds = 0; Timer? _refreshTimer; @override void initState() { super.initState(); _initPrefsAndRestoreTimer(); } // 初始化SharedPreferences并恢复计时状态 Future<void> _initPrefsAndRestoreTimer() async { _prefs = await SharedPreferences.getInstance(); _endTimeMillis = _prefs.getInt('timer_end_timestamp'); _calculateRemainingTime(); _startRefreshTimer(); } // 计算并更新剩余时间 void _calculateRemainingTime() { if (_endTimeMillis == null) { setState(() => _remainingSeconds = 0); return; } final now = DateTime.now().millisecondsSinceEpoch; final remainingMillis = _endTimeMillis! - now; if (remainingMillis <= 0) { // 计时已结束,清除存储的时间戳 setState(() => _remainingSeconds = 0); _prefs.remove('timer_end_timestamp'); _endTimeMillis = null; _refreshTimer?.cancel(); } else { setState(() => _remainingSeconds = (remainingMillis / 1000).ceil()); } } // 启动每秒刷新UI的计时器 void _startRefreshTimer() { _refreshTimer?.cancel(); if (_endTimeMillis != null && _remainingSeconds > 0) { _refreshTimer = Timer.periodic(const Duration(seconds: 1), (_) { _calculateRemainingTime(); }); } } // 触发开始计时(示例为60秒计时) void _triggerTimer() { const totalCountdownSeconds = 60; final now = DateTime.now().millisecondsSinceEpoch; _endTimeMillis = now + totalCountdownSeconds * 1000; // 存储结束时间戳 _prefs.setInt('timer_end_timestamp', _endTimeMillis!); _calculateRemainingTime(); _startRefreshTimer(); } @override void dispose() { _refreshTimer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('后台持续计时器')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '剩余时间: $_remainingSeconds 秒', style: const TextStyle(fontSize: 24), ), const SizedBox(height: 20), ElevatedButton( onPressed: _remainingSeconds > 0 ? null : _triggerTimer, child: const Text('开始60秒计时'), ), ], ), ), ); } }
补充说明
- 这个方案不依赖后台服务,完全靠系统时间和存储的结束时间戳计算,即使应用被杀死,重启后也能立即得到真实剩余时长。
- 如果需要后台提醒(比如计时结束推送通知),可以搭配
flutter_local_notifications库,在_calculateRemainingTime中判断剩余时间为0时发送通知即可。
内容的提问来源于stack exchange,提问作者Enns
相关产品推荐
相关产品推荐

