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

Flutter中结合Change Notifier使用Shared Preferences的问题求助

问题:Flutter中结合ChangeNotifier与SharedPreferences实现状态持久化

我正在学习如何在Flutter中结合Change Notifier使用Shared Preferences,已创建一个基础应用,希望通过Shared Preferences保存Change Notifier中的bool类型值和string类型值。

main.dart 代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => GlobalSettings1()),
        ChangeNotifierProvider(create: (_) => SectionSettings1()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        initialRoute: '/seventh',
        routes: {
          '/': (context) => Page01(),
          '/first': (context) => Page02(),
          '/second': (context) => Page03(),
        });
  }
}

Page01 代码

class _Page01State extends State<Page01> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          InkWell(
            onTap: () {
              context.read<GlobalSettings1>().ToggleSwitch();
            },
            child: Container(
              height: 30,
              width: 80,
              color: context.watch<GlobalSettings1>().toggleSwitch01
                  ? Colors.green
                  : Colors.red,
            ),
          ),
          SizedBox(
            height: 20,
          ),
          InkWell(
              onTap: () {
                showDialog(
                  context: context,
                  builder: (BuildContext context) => Material(
                    color: Colors.transparent,
                    child: Buttons(
                      onTap: (val) {
                        context.read<GlobalSettings1>().StringToSave(val);
                        Navigator.pop(context);
                      },
                    ),
                  ),
                );
              },
              child: Container(
                height: 30,
                width: 80,
                child: Center(
                  child: Text(
                    context.watch()<GlobalSettings1>().stringToSave,
                  ),
                ),
              )),
        ],
      ),
    );
  }
}

Change Notifier 代码

class Buttons extends StatelessWidget {
  const Buttons({Key? key, required this.onTap}) : super(key: key);
  final ValueChanged? onTap;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        InkWell(
            onTap: () {
              if (onTap != null) {
                onTap!('Choice01');
              }
            },
            child: Container(
              height: 30,
              width: 80,
              child: Text('Choice01'),
            )),
        SizedBox(
          height: 30,
        ),
        InkWell(
            onTap: () {
              if (onTap != null) {
                onTap!('Choice02');
              }
            },
            child: Container(
              height: 30,
              width: 80,
              child: Text('Choice02'),
            )),
      ],
    );
  }
}

class GlobalSettings1 with ChangeNotifier {
  bool _toggleSwitch01 = true;
  String _stringToSave = 'Choice01';

  final SharedPreferences prefs;

  GlobalSettings1({required this.prefs});

  bool get toggleSwitch01 => _toggleSwitch01;
  String get stringToSave => _stringToSave;

  void ToggleSwitch() {
    _toggleSwitch01 = !_toggleSwitch01;
    _setPrefItems();
    notifyListeners();
  }

  void StringToSave(val) {
    _stringToSave = val;
    _setPrefItems();
    notifyListeners();
  }

  void _setPrefItems() {
    prefs.setBool('toggleSwitch01', _toggleSwitch01);
    prefs.setString('stringToSave', _stringToSave);
    notifyListeners();
  }

  void _getPrefItems() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    _stringToSave = prefs.getString('stringToSave') ?? '';
    _toggleSwitch01 = prefs.getBool('autoUpdateVariables') ?? true;
    notifyListeners();
  }

  bool getToggleSwitch01() {
    _getPrefItems();
    return _toggleSwitch01;
  }

  String getStringToSave() {
    _getPrefItems();
    return _stringToSave;
  }
}

核心问题

  1. main.dart中ChangeNotifierProvider(create: (_) => GlobalSettings1())提示需要必填参数prefs,不知道该如何传入;
  2. 不确定如何配置main.dart和Page01,使得APP重启后,之前设置的bool值和string值能保持。

解决方案

1. 修改main函数,异步初始化SharedPreferences

SharedPreferences.getInstance()是异步操作,需要先完成初始化再启动App,修改main.dart的main函数:

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // 确保Flutter绑定初始化
  final prefs = await SharedPreferences.getInstance();
  
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => GlobalSettings1(prefs: prefs)),
        ChangeNotifierProvider(create: (_) => SectionSettings1()),
      ],
      child: MyApp(),
    ),
  );
}

2. 修正GlobalSettings1的状态加载逻辑

当前_getPrefItems存在重复获取实例、键名错误的问题,同时需要在构造函数中自动加载保存的状态:

class GlobalSettings1 with ChangeNotifier {
  bool _toggleSwitch01 = true;
  String _stringToSave = 'Choice01';

  final SharedPreferences prefs;

  // 构造函数中自动加载保存的配置
  GlobalSettings1({required this.prefs}) {
    _loadPrefs();
  }

  bool get toggleSwitch01 => _toggleSwitch01;
  String get stringToSave => _stringToSave;

  void ToggleSwitch() {
    _toggleSwitch01 = !_toggleSwitch01;
    _savePrefs();
    notifyListeners();
  }

  void StringToSave(String val) {
    _stringToSave = val;
    _savePrefs();
    notifyListeners();
  }

  // 保存配置到SharedPreferences
  void _savePrefs() {
    prefs.setBool('toggleSwitch01', _toggleSwitch01);
    prefs.setString('stringToSave', _stringToSave);
  }

  // 加载保存的配置
  void _loadPrefs() {
    _stringToSave = prefs.getString('stringToSave') ?? 'Choice01';
    _toggleSwitch01 = prefs.getBool('toggleSwitch01') ?? true; // 修正键名错误
    notifyListeners();
  }

  // 移除冗余的getToggleSwitch01和getStringToSave方法,直接通过getter获取状态
}

3. 修复Page01中的语法错误

Page01中Text组件的context.watch()写法错误,修正为:

child: Text(
  context.watch<GlobalSettings1>().stringToSave,
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:35:26