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

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初始化和登录状态读取,从根源上避免初始页闪烁问题,逻辑更清晰:

  1. 先修改入口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));
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:27:25