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

Flutter Cubit初始化状态异常求助:SharedPreferences读取值不生效

饮水量追踪器Cubit初始化状态问题解决方案

问题背景

我正处于Cubit学习初期,尝试使用SharedPreferences开发一款“Liter-Tracker”(饮水量追踪器)。目前各项功能基本正常,但初始化状态存在问题:由于drinkValue初始值设为0,我必须先点击按钮才能读取SharedPreferences中存储的值。我尝试从SharedPreferences返回整数来初始化状态,但并未成功。

现有代码

DrinkCubit代码

class DrinkCubit extends Cubit<DrinkState> {
  DrinkCubit() : super(DrinkState(drinkValue: 0));


  Future<void> loadCounter() async {
    final prefs = await SharedPreferences.getInstance();

    state.drinkValue = (prefs.getInt('counter') ?? 0);
  }


  Future<int> loadInitCounter() async {
    final prefs = await SharedPreferences.getInstance();

    return state.drinkValue = (prefs.getInt('counter') ?? 0);
  }

}

DrinkState代码

class DrinkState {
  int drinkValue;
  int? amount;

  DrinkState({
    required this.drinkValue,

});

}

页面初始化尝试

@override
void initState() {
  super.initState();
  BlocProvider.of<DrinkCubit>(context).loadCounter();
}

核心问题分析

  1. DrinkState不是不可变类:Cubit的状态必须是不可变的,直接修改state.drinkValue不会触发UI更新,因为Cubit依赖发送新状态实例来通知监听者。
  2. 未正确发送新状态:加载SharedPreferences后,只是修改了现有state的属性,没有调用emit()方法发布新状态,导致UI无法感知到值的变化。

修复步骤

1. 将DrinkState改为不可变类

给成员变量添加final修饰,同时实现copyWith方法方便生成新状态:

class DrinkState {
  final int drinkValue;
  final int? amount;

  const DrinkState({
    required this.drinkValue,
    this.amount,
  });

  // 生成新状态的便捷方法
  DrinkState copyWith({
    int? drinkValue,
    int? amount,
  }) {
    return DrinkState(
      drinkValue: drinkValue ?? this.drinkValue,
      amount: amount ?? this.amount,
    );
  }
}

2. 修改DrinkCubit逻辑

去掉直接修改state的操作,加载存储值后通过emit()发送新状态,同时可以在构造函数中自动执行加载逻辑,无需页面手动调用:

class DrinkCubit extends Cubit<DrinkState> {
  DrinkCubit() : super(const DrinkState(drinkValue: 0)) {
    // 初始化时自动加载存储的饮水量数据
    _loadSavedDrinkValue();
  }

  Future<void> _loadSavedDrinkValue() async {
    final prefs = await SharedPreferences.getInstance();
    final savedValue = prefs.getInt('counter') ?? 0;
    // 发送新状态更新UI
    emit(state.copyWith(drinkValue: savedValue));
  }

  // 示例:增加饮水量的方法(包含存储逻辑)
  Future<void> addDrink(int amount) async {
    final newValue = state.drinkValue + amount;
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('counter', newValue);
    emit(state.copyWith(drinkValue: newValue));
  }
}

3. 页面初始化(可选)

如果不需要在Cubit构造函数自动加载,也可以在页面initState中调用公开的加载方法:

@override
void initState() {
  super.initState();
  // 注意要将_loadSavedDrinkValue改为公开方法(去掉下划线)
  context.read<DrinkCubit>().loadSavedDrinkValue();
}

关键说明

  • Cubit的状态更新必须通过emit()方法发送新的不可变状态实例,直接修改现有state不会触发UI刷新。
  • 不可变状态类能保证状态变化的可追踪性,避免出现难以调试的状态不一致问题。
  • 在Cubit构造函数中自动执行初始化逻辑,能让页面打开时直接展示存储的数据,无需用户手动触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 09:45:46