Flutter中SharedPreferences初始化延迟引发LateInitializationError问题解决
问题根源在于你用late修饰了_isEditingText和initialText,但这两个变量是在异步方法initializePreference中初始化的。Flutter会在initState执行后立刻调用build方法,此时异步操作还未完成,late变量还没被赋值,直接访问就会触发LateInitializationError,导致红屏。
下面是两种可行的解决方式:
方式一:使用可空变量+加载状态判断
把late修饰的变量改成可空类型,在build方法中先判断变量是否初始化完成,未完成时显示加载UI,避免直接访问未初始化的变量。
修改后的代码示例:
bool? _isEditingText; TextEditingController _editingController = TextEditingController(); String? initialText; SharedPreferences? _prefs; @override void initState(){ super.initState(); initializePreference(); } Future<void> initializePreference() async{ _prefs = await SharedPreferences.getInstance(); String? name = _prefs?.getString('name'); if (name == null) { _isEditingText = true; initialText = 'Enter ur name'; } else { _isEditingText = false; initialText = name; } // 初始化完成后刷新UI,判断组件是否已挂载避免警告 if(mounted) setState(() {}); } @override Widget build(BuildContext context) { // 未初始化完成时显示加载组件 if (_isEditingText == null || initialText == null) { return const Center(child: CircularProgressIndicator()); } // 初始化完成后的正常页面UI return Scaffold( body: TextField( controller: _editingController..text = initialText!, enabled: _isEditingText!, // 其他TextField配置 ), ); }
方式二:使用FutureBuilder管理异步状态
通过FutureBuilder监听异步初始化的状态,统一处理加载中、加载完成、加载失败的场景,代码结构更清晰。
修改后的代码示例:
late bool _isEditingText; TextEditingController _editingController = TextEditingController(); late String initialText; SharedPreferences? _prefs; // 保存初始化的Future,避免每次build都重新执行异步操作 late Future<void> _initFuture; @override void initState(){ super.initState(); _initFuture = initializePreference(); } Future<void> initializePreference() async{ _prefs = await SharedPreferences.getInstance(); String? name = _prefs?.getString('name'); if (name == null) { _isEditingText = true; initialText = 'Enter ur name'; } else { _isEditingText = false; initialText = name; } } @override Widget build(BuildContext context) { return FutureBuilder( future: _initFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // 加载中显示转圈 return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { // 加载失败显示错误提示 return Center(child: Text('加载失败: ${snapshot.error}')); } else { // 加载完成显示正常UI return Scaffold( body: TextField( controller: _editingController..text = initialText, enabled: _isEditingText, // 其他TextField配置 ), ); } }, ); }
关键注意点
- 无论哪种方式,都要确保在变量初始化完成前,不要让
build方法访问未初始化的变量。 - 使用
setState时建议加上if(mounted)判断,避免组件已销毁时调用setState引发警告。 - 方式二中的
_initFuture要在initState中初始化,不要直接在FutureBuilder的future参数中写initializePreference(),否则每次build都会重新执行异步操作。
内容的提问来源于stack exchange,提问作者S.Beigi
相关产品推荐
相关产品推荐

