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

Flutter饮水提醒APP页面切换数据重置问题求助

Flutter饮水提醒APP状态重置问题解决方法

问题核心

切换页面后计数器和当日记录重置,本质是页面状态未做持久化存储,且你之前尝试的SharedPreferences用法存在多处错误:

  • 直接将ValueNotifier<List<DrinkRecordModel>>强转为List<String>,无法正确序列化自定义模型
  • _getData方法未将读取到的赋值给变量,仅调用了读取方法但未更新状态
  • 数据发生变化时未触发保存操作

分步修复方案

1. 给自定义模型添加序列化能力

SharedPreferences只能存储基础数据类型,需要把DrinkRecordModel转成可序列化的格式(比如JSON),修改模型类:

import 'dart:convert';

class DrinkRecordModel {
  final String time;
  final String amountOfWater;

  DrinkRecordModel({required this.time, required this.amountOfWater});

  // 转成Map用于序列化
  Map<String, dynamic> toMap() {
    return {
      'time': time,
      'amountOfWater': amountOfWater,
    };
  }

  // 从Map反序列化回模型
  factory DrinkRecordModel.fromMap(Map<String, dynamic> map) {
    return DrinkRecordModel(
      time: map['time'] ?? '',
      amountOfWater: map['amountOfWater'] ?? '',
    );
  }
}

2. 修复SharedPreferences操作逻辑

修改首页的存储和读取方法,正确处理数据持久化:

import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class _HomeState extends State<Home> {
  static const _amountKey = 'total_drink_amount';
  static const _recordsKey = 'drink_records_list';

  late ValueNotifier<List<DrinkRecordModel>> _items;
  double amount = 0;

  // 保存数据到本地
  void _saveData() async {
    final prefs = await SharedPreferences.getInstance();
    // 保存总饮水量
    await prefs.setDouble(_amountKey, amount);
    // 将记录列表转成JSON字符串列表存储
    final recordsJson = _items.value.map((record) => jsonEncode(record.toMap())).toList();
    await prefs.setStringList(_recordsKey, recordsJson);
  }

  // 从本地加载数据
  Future<void> _getData() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      // 读取总饮水量,默认值为0
      amount = prefs.getDouble(_amountKey) ?? 0;
      // 读取记录并反序列化
      final recordsJson = prefs.getStringList(_recordsKey);
      if (recordsJson != null) {
        _items.value = recordsJson.map((json) => DrinkRecordModel.fromMap(jsonDecode(json))).toList();
      } else {
        // 无本地数据时初始化默认记录
        _items.value = [
          DrinkRecordModel(
            time: '11:00 AM',
            amountOfWater: changeUnit(),
          ),
        ];
      }
    });
  }

3. 正确初始化和触发保存

  • 在页面初始化时加载本地数据:
@override
void initState() {
  super.initState();
  _items = ValueNotifier([]);
  _getData(); // 启动时加载保存的数据
}
  • 在所有数据变化的场景调用保存方法:
    • 点击添加饮水量时:
    onTap: () {
      setState(() {
        widget.unit == 'kilograms' ? amount += 175 : amount += 6;
        _items.value.add(DrinkRecordModel(
          time: TimeOfDay.now().format(context),
          amountOfWater: changeUnit(),
        ));
      });
      _saveData(); // 保存更新后的数据
    },
    
    • 删除记录时(注意同步更新总饮水量):
    void _deleteItem(int index) {
      final deletedRecord = _items.value[index];
      final deletedAmount = double.parse(deletedRecord.amountOfWater.split(' ')[0]);
      setState(() {
        _items.value.removeAt(index);
        amount -= deletedAmount;
      });
      _saveData();
    }
    
    • 编辑记录完成后:
    ElevatedButton(
      child: Text('Save'),
      onPressed: () {
        _items.notifyListeners();
        Navigator.pop(context);
        _saveData(); // 保存编辑后的记录
      },
    )
    

4. 避免页面重建导致状态丢失

如果切换页面时首页被销毁重建,上述持久化逻辑会在initState重新加载数据,完全覆盖初始化的默认值,确保状态不会丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:52:31