Flutter技术问询:Shared Preferences启动时值为空如何解决
兄弟,我太懂这种异步初始化踩坑的感觉了!你遇到的问题本质上是Shared Preferences的初始化是异步操作——应用刚启动时你直接调用prefs.getBool('myBool'),此时Shared Preferences还没完成从本地文件加载数据的过程,自然返回null;而点击按钮时,这个异步操作已经完成了,所以能拿到正确的值。
下面给你几种实用的解决方案,你可以根据自己的应用场景选择:
方案1:在main函数中等待Shared Preferences初始化
这是最直接的方式,确保整个应用在Shared Preferences加载完成后再启动,从根源避免null的问题:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { // 必须先初始化Flutter绑定,否则异步操作会报错 WidgetsFlutterBinding.ensureInitialized(); // 等待Shared Preferences初始化完成 final prefs = await SharedPreferences.getInstance(); // 给个默认值兜底,防止首次安装时没有保存过值 final myBool = prefs.getBool('myBool') ?? false; runApp(MyApp(initialMyBool: myBool)); } class MyApp extends StatelessWidget { final bool initialMyBool; const MyApp({super.key, required this.initialMyBool}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Text('应用启动时的初始值:$initialMyBool'), ), ), ); } }
方案2:用FutureBuilder在页面中异步等待加载
如果不想阻塞整个应用启动(比如要先显示启动页),可以在需要用到值的页面用FutureBuilder处理异步状态,给用户展示加载状态:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late Future<bool> _myBoolFuture; @override void initState() { super.initState(); // 页面初始化时就发起Shared Preferences的获取请求 _myBoolFuture = _getMyBool(); } Future<bool> _getMyBool() async { final prefs = await SharedPreferences.getInstance(); return prefs.getBool('myBool') ?? false; } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<bool>( future: _myBoolFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // 加载中显示进度条,避免用户看到空白或null return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return const Center(child: Text('加载设置出错啦')); } else { // 加载完成,展示正确的值 final myBool = snapshot.data!; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('当前值:$myBool'), ElevatedButton( onPressed: () async { final prefs = await SharedPreferences.getInstance(); await prefs.setBool('myBool', !myBool); // 更新Future,刷新UI展示新值 setState(() { _myBoolFuture = _getMyBool(); }); }, child: const Text('切换布尔值'), ) ], ), ); } }, ), ); } }
方案3:用状态管理工具全局共享(适合复杂应用)
如果你的应用有多个页面需要用到Shared Preferences的值,用状态管理工具(比如Provider)来提前初始化并全局共享是更优雅的选择:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:provider/provider.dart'; class AppSettings extends ChangeNotifier { bool _myBool = false; late SharedPreferences _prefs; bool get myBool => _myBool; AppSettings() { // 类初始化时自动完成Shared Preferences的加载 _initSettings(); } Future<void> _initSettings() async { _prefs = await SharedPreferences.getInstance(); _myBool = _prefs.getBool('myBool') ?? false; // 通知监听者更新UI notifyListeners(); } Future<void> toggleMyBool() async { _myBool = !_myBool; await _prefs.setBool('myBool', _myBool); notifyListeners(); } } void main() async { WidgetsFlutterBinding.ensureInitialized(); runApp( ChangeNotifierProvider( create: (context) => AppSettings(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Consumer<AppSettings>( builder: (context, settings, child) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('全局共享的布尔值:${settings.myBool}'), ElevatedButton( onPressed: () => settings.toggleMyBool(), child: const Text('切换值'), ) ], ), ); }, ), ), ); } }
核心思路总结
不管用哪种方案,核心都是确保在获取Shared Preferences的值之前,先等待它的初始化异步操作完成。上面三种方案分别对应了:
- 简单应用的全局阻塞初始化
- 页面级的异步等待(不阻塞启动)
- 复杂应用的全局状态管理
你可以根据自己的应用规模和需求来选~
内容的提问来源于stack exchange,提问作者PityTheFool
相关产品推荐
相关产品推荐

