You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中支持暂停/继续的持久化计时器问题求助

解决方案:持久化完整计时器状态

要解决应用被杀后计时器归零的问题,同时支持暂停/继续功能,核心是完整持久化计时器的运行状态和关键时间数据,而非单一存储起始时间或当前值。以下是具体实现思路:

需要持久化的核心数据

用shared_preferences存储三组关键信息:

  • isRunning:布尔值,标记计时器当前处于运行中还是暂停状态
  • elapsedMilliseconds:累计已完成的计时时长(毫秒),暂停状态下直接用该值恢复计时
  • lastStartTime:最后一次启动计时的时间戳(毫秒),仅在运行状态下有效,用于重启后计算从上次启动到当前的流逝时间

具体实现逻辑

1. 应用启动时恢复状态

从shared_preferences读取保存的状态:

  • 若为暂停状态:直接将elapsedMilliseconds赋值给stop_watch_timer的初始值
  • 若为运行状态:计算当前时间戳 - lastStartTime,加上elapsedMilliseconds得到总时长,赋值给计时器后继续启动计时

2. 响应用户操作更新状态

  • 点击开始/继续:记录当前时间戳为lastStartTime,设置isRunning为true,持久化这两个值
  • 点击暂停:读取stop_watch_timer的当前值作为elapsedMilliseconds,设置isRunning为false,持久化这两个值

3. 后台自动保存状态

通过WidgetsBindingObserver监听应用生命周期,当应用进入后台(AppLifecycleState.paused)时自动保存当前状态:

  • 运行中:计算当前累计时长,更新elapsedMilliseconds为「截止上次启动前的累计时长」,同时更新lastStartTime为当前时间戳
  • 暂停中:直接读取计时器当前值更新elapsedMilliseconds

代码示例片段

import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';

class TimerManager with WidgetsBindingObserver {
  final StopWatchTimer stopWatchTimer = StopWatchTimer();
  late SharedPreferences _prefs;
  bool _isRunning = false;
  int _elapsedMilliseconds = 0;
  int _lastStartTime = 0;

  Future<void> init() async {
    _prefs = await SharedPreferences.getInstance();
    WidgetsBinding.instance.addObserver(this);
    // 读取本地存储的状态
    _isRunning = _prefs.getBool('isRunning') ?? false;
    _elapsedMilliseconds = _prefs.getInt('elapsedMilliseconds') ?? 0;
    _lastStartTime = _prefs.getInt('lastStartTime') ?? 0;

    if (_isRunning) {
      final now = DateTime.now().millisecondsSinceEpoch;
      final totalElapsed = _elapsedMilliseconds + (now - _lastStartTime);
      stopWatchTimer.setPresetTime(mSec: totalElapsed);
      stopWatchTimer.onExecute.add(StopWatchExecute.start);
      _lastStartTime = now;
      await _saveState();
    } else {
      stopWatchTimer.setPresetTime(mSec: _elapsedMilliseconds);
    }
  }

  Future<void> toggleTimer() async {
    if (_isRunning) {
      stopWatchTimer.onExecute.add(StopWatchExecute.stop);
      _isRunning = false;
      _elapsedMilliseconds = stopWatchTimer.rawTime.value;
    } else {
      stopWatchTimer.onExecute.add(StopWatchExecute.start);
      _isRunning = true;
      _lastStartTime = DateTime.now().millisecondsSinceEpoch;
    }
    await _saveState();
  }

  Future<void> _saveState() async {
    await _prefs.setBool('isRunning', _isRunning);
    await _prefs.setInt('elapsedMilliseconds', _elapsedMilliseconds);
    await _prefs.setInt('lastStartTime', _lastStartTime);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.paused) {
      if (_isRunning) {
        final currentElapsed = stopWatchTimer.rawTime.value;
        _elapsedMilliseconds = currentElapsed - (DateTime.now().millisecondsSinceEpoch - _lastStartTime);
        _lastStartTime = DateTime.now().millisecondsSinceEpoch;
      } else {
        _elapsedMilliseconds = stopWatchTimer.rawTime.value;
      }
      _saveState();
    }
  }

  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    stopWatchTimer.dispose();
  }
}

方案优势

  • 兼容运行、暂停两种状态下的应用被杀场景,重启后完全恢复之前的计时状态
  • 基于shared_preferences实现,无需依赖复杂插件,性能稳定
  • 通过生命周期监听自动保存状态,无需用户手动触发,体验流畅

内容的提问来源于stack exchange,提问作者Sparkringo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:55:29