Flutter读取SharedPreferences后bool变量未更新导致路由跳转错误
问题根因
comprobarEstado()是异步方法,initState中调用该方法时不会等待其执行完成就会触发首次build,此时isLoggedIn仍为初始值false;异步方法执行完成、给isLoggedIn赋值后,没有调用setState()通知框架触发UI重建,因此页面始终展示首次构建的LoginScreen,即便日志打印的变量值正确,UI也不会同步更新。
实现方案
方案1:原有逻辑最小改动
仅需在异步获取到登录状态后调用setState触发UI重建即可,建议额外增加初始化加载态,避免异步等待期间错误展示登录页:
class _MyAppState extends State<MyApp> { // 初始化加载状态标识 bool isLoading = true; bool isLoggedIn = false; @override void initState() { super.initState(); comprobarEstado(); } Future<void> comprobarEstado() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); // 用空合并运算符简化判空逻辑,无需额外强转 isLoggedIn = prefs.getBool('logeado') ?? false; // 赋值完成后关闭加载态,触发UI重建 setState(() { isLoading = false; }); print("Estado ${isLoggedIn}"); } @override Widget build(BuildContext context) { return MaterialApp( localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, locale: context.locale, theme: ThemeData( primarySwatch: Colors.blue, ), // 加载过程中展示居中加载指示器,避免页面闪烁 home: isLoading ? const Scaffold(body: Center(child: CircularProgressIndicator())) : isLoggedIn ? const MyHomePage() : const LoginScreen() ); } }
方案2:生产环境推荐实现
直接在应用启动入口完成SharedPreferences初始化和登录状态读取,从根源上避免初始页闪烁问题,逻辑更清晰:
- 先修改入口
main函数,在runApp前完成所有异步初始化:
void main() async { // 确保插件服务绑定初始化,否则启动前的异步调用会报错 WidgetsFlutterBinding.ensureInitialized(); // 应用启动前同步获取SharedPreferences实例和登录状态 final SharedPreferences prefs = await SharedPreferences.getInstance(); final bool isLoggedIn = prefs.getBool('logeado') ?? false; runApp(MyApp(isLoggedIn: isLoggedIn)); }
- 修改
MyApp组件,通过构造函数接收初始化好的登录状态,无需在组件生命周期内做异步请求:
class MyApp extends StatefulWidget { final bool isLoggedIn; const MyApp({super.key, required this.isLoggedIn}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { late bool isLoggedIn; @override void initState() { super.initState(); isLoggedIn = widget.isLoggedIn; } // 提供更新登录状态的方法,供登录、退出逻辑调用 void updateLoginStatus(bool status) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setBool('logeado', status); setState(() { isLoggedIn = status; }); } @override Widget build(BuildContext context) { return MaterialApp( localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, locale: context.locale, theme: ThemeData( primarySwatch: Colors.blue, ), home: isLoggedIn ? const MyHomePage() : const LoginScreen() ); } }
该方案的优势:
- 应用启动第一帧就加载正确页面,不会出现先展示登录页再跳转首页的闪烁问题
- 不需要额外处理初始化加载状态,逻辑链路更短
- 登录状态初始化入口统一,后续维护、扩展状态逻辑更方便
注意:无论使用哪种方案,后续用户执行登录、退出操作时,除了更新SharedPreferences中存储的状态值,都要同步调用
setState更新isLoggedIn变量,才能触发页面切换。
内容的提问来源于stack exchange,提问作者mvasco
相关产品推荐
相关产品推荐

