Flutter中Widget无法加载更新shared_preferences存储数据的问题
问题核心原因
TextFormField的initialValue属性仅在组件首次挂载初始化时生效一次,后续哪怕父组件调用setState更新了max变量,已经完成初始化的输入框不会重新读取initialValue做更新,这就是数据读取成功、setState也触发了但界面不显示存储值的核心原因。_loadMax()方法直接写在build方法中存在逻辑风险:build方法会在每次组件重建时触发,虽然加了max == null的判断,但异步调用时序不可控,极端场景下会重复触发初始化逻辑。- 首次进入页面无存储值时,调用
_setMax(16)的分支没有同步处理当前页面的状态更新,会导致默认值加载异常。 SharedPreferences实例初始化没有放在组件专属的初始化生命周期钩子中,不符合Flutter状态管理规范。- 原代码存在隐藏崩溃风险:
max为null时max.toString()会得到字符串"null"作为输入框初始值,同时输入正则允许输入小数点,但存储逻辑按int类型解析,输入小数时会触发类型转换错误。
修复步骤
- 把预加载逻辑从
build方法移到initState生命周期中,确保组件挂载时只执行一次数据读取。 - 新增
TextEditingController控制输入框文本内容,替代initialValue实现数据更新后的界面同步,controller支持在任意时机主动设置输入框文本,不受组件初始化时机限制。 - 补全默认值设置分支的状态同步逻辑,确保首次加载默认值时也能正常触发界面更新。
- 组件销毁时回收
TextEditingController,避免内存泄漏。 - 修正输入格式正则和空值判断,移除小数点匹配规则,避免解析崩溃。
修复后完整代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Settings extends StatefulWidget { const Settings({Key? key}) : super(key: key); @override State<Settings> createState() => _SettingsState(); } class _SettingsState extends State<Settings> { late SharedPreferences preferences; int? max; late TextEditingController _maxInputController; @override void initState() { super.initState(); _maxInputController = TextEditingController(); // 组件初始化时统一加载存储数据 _loadMax(); } @override void dispose() { // 销毁时回收控制器 _maxInputController.dispose(); super.dispose(); } _loadMax() async { preferences = await SharedPreferences.getInstance(); if (!preferences.containsKey('max')) { await _setMax(16); } else { max = preferences.getInt('max'); // 直接给控制器赋值,同步输入框显示 _maxInputController.text = max.toString(); setState(() {}); } } _setMax(int value) async { await preferences.setInt('max', value); max = value; // 同步更新输入框文本 _maxInputController.text = value.toString(); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Max Number (Inclusive) ', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(width: 10.0), SizedBox( width: 100, height: 50, child: TextFormField( controller: _maxInputController, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: 'Maximum', counterText: '', ), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r"[0-9]")), ], onFieldSubmitted: (s) { if(s.isNotEmpty) { _setMax(int.parse(s)); } }, maxLength: 4, keyboardType: TextInputType.number, ), ), ], ), ElevatedButton( onPressed: () => Navigator.pop(context), child: const Text('Home'), ), ]), ); } }
内容的提问来源于stack exchange,提问作者user19309046
相关产品推荐
相关产品推荐

