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

Flutter中如何基于DateTime.now()实现支持后台续接的倒计时?

实现持久化实时倒计时功能

核心思路

要实现关闭应用后重新打开仍能继续计时的倒计时,关键是持久化存储倒计时的结束时间,而非每次启动都使用初始时长。每次启动时通过当前时间与存储的结束时间的差值,计算剩余倒计时时长,再实时更新UI。

实现步骤(以Flutter为例)

  1. 首次启动时,计算初始结束时间:当前时间 + 初始倒计时时长,将该结束时间存入本地存储。
  2. 后续启动时,读取存储的结束时间,对比当前时间计算剩余时长。
  3. 用计时器每秒更新剩余时间,同步到UI显示。

完整代码示例

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

class CountdownPage extends StatefulWidget {
  const CountdownPage({super.key});

  @override
  State<CountdownPage> createState() => _CountdownPageState();
}

class _CountdownPageState extends State<CountdownPage> {
  Duration _remainingTime = Duration.zero;
  Timer? _timer;
  final String _endTimeKey = 'countdown_end_time';
  // 初始倒计时时长:5小时23分23秒
  final Duration _initialDuration = const Duration(hours: 5, minutes: 23, seconds: 23);

  @override
  void initState() {
    super.initState();
    _initCountdown();
  }

  Future<void> _initCountdown() async {
    final prefs = await SharedPreferences.getInstance();
    final String? endTimeStr = prefs.getString(_endTimeKey);
    
    DateTime endTime;
    if (endTimeStr == null) {
      // 首次启动,计算并存储初始结束时间
      endTime = DateTime.now().add(_initialDuration);
      await prefs.setString(_endTimeKey, endTime.toIso8601String());
    } else {
      // 读取已存储的结束时间
      endTime = DateTime.parse(endTimeStr);
    }

    _updateRemainingTime(endTime);
    // 每秒更新一次剩余时间
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      _updateRemainingTime(endTime);
    });
  }

  void _updateRemainingTime(DateTime endTime) {
    final now = DateTime.now();
    if (now.isAfter(endTime)) {
      // 倒计时已结束
      setState(() {
        _remainingTime = Duration.zero;
      });
      _timer?.cancel();
      // 可选:清除存储,下次启动重置倒计时
      // _clearStoredEndTime();
    } else {
      setState(() {
        _remainingTime = endTime.difference(now);
      });
    }
  }

  Future<void> _clearStoredEndTime() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_endTimeKey);
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 格式化剩余时间为 HH:mm:ss 格式
    String formattedTime = '${_remainingTime.inHours.toString().padLeft(2, '0')}:'
        '${(_remainingTime.inMinutes % 60).toString().padLeft(2, '0')}:'
        '${(_remainingTime.inSeconds % 60).toString().padLeft(2, '0')}';

    return Scaffold(
      appBar: AppBar(title: const Text('倒计时')),
      body: Center(
        child: Text(
          formattedTime,
          style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

关键细节说明

  • 持久化选择:使用SharedPreferences存储结束时间(ISO8601字符串格式),相比存储剩余时间,能避免设备时间调整、应用后台被杀死等场景下的计时偏差。
  • 实时更新:通过Timer.periodic每秒触发一次时间计算,确保UI与当前时间同步。
  • 边界处理:当当前时间超过结束时间时,自动停止计时器并显示00:00:00,可根据需求选择是否清除存储以重置倒计时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 16:22:32