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

Flutter项目启动页因Firebase登录逻辑冻结问题求助

Flutter启动页冻结问题:仅显示UI无法完成跳转

我正在开发一个Flutter项目,启动页逻辑如下:

  • 检查SharedPreference中是否存在登录凭证
  • 若存在,尝试通过Firebase自动登录:
    • 登录无异常则跳转HomeScreen
    • 出现错误则重置凭证并跳转LoginOrSignUp页
  • 若不存在凭证则直接跳转LoginOrSignUp页

目前启动页出现冻结问题,仅能显示UI,无法完成后续跳转逻辑。

getDataAndCheck函数代码

void getDataAndCheck() async {
    bool emailPresent = await sharedPreference().checkValuePresent('email');
    bool passwordPresent =
        await sharedPreference().checkValuePresent('password');
    email = (await sharedPreference().getCred('email')) ?? '';
    password = (await sharedPreference().getCred('password')) ?? '';
    Timer(const Duration(seconds: 3), () {
      print('Email: $email\nPassword: $password');
      if (emailPresent == true && passwordPresent == true) {
        print('inside if');
        firebaseAuth
            .signInWithEmailAndPassword(email: email, password: password)
            .catchError((errMsg) {
          print('inside catch error');
          if (errMsg.code == null) {
            print('When Null');
            Navigator.pushAndRemoveUntil(
              context,
              PageRouteBuilder(
                transitionDuration: const Duration(seconds: 1),
                transitionsBuilder: (context, animation, animationTime, child) {
                  animation = CurvedAnimation(
                      parent: animation, curve: Curves.fastLinearToSlowEaseIn);
                  return ScaleTransition(
                    scale: animation,
                    alignment: Alignment.center,
                    child: child,
                  );
                },
                pageBuilder: (context, animation, animationTime) {
                  return const HomeScreen();
                },
              ),
              (route) => false,
            );
          } else {
            print('When Not Null');
            sharedPreference().reset();
            Navigator.pushReplacement(
              context,
              PageRouteBuilder(
                transitionDuration: const Duration(seconds: 1),
                transitionsBuilder: (context, animation, animationTime, child) {
                  animation = CurvedAnimation(
                      parent: animation, curve: Curves.fastLinearToSlowEaseIn);
                  return ScaleTransition(
                    scale: animation,
                    alignment: Alignment.center,
                    child: child,
                  );
                },
                pageBuilder: (context, animation, animationTime) {
                  return const LoginOrSignUp();
                },
              ),
            );
          }
        });
      } else {
        print('When email and password in not present');
        sharedPreference().reset();
        Navigator.pushReplacement(
          context,
          PageRouteBuilder(
            transitionDuration: const Duration(seconds: 1),
            transitionsBuilder: (context, animation, animationTime, child) {
              animation = CurvedAnimation(
                  parent: animation, curve: Curves.fastLinearToSlowEaseIn);
              return ScaleTransition(
                scale: animation,
                alignment: Alignment.center,
                child: child,
              );
            },
            pageBuilder: (context, animation, animationTime) {
              return const LoginOrSignUp();
            },
          ),
        );
      }
    });
  }

initState调用代码

@override
  void initState() {
    super.initState();
    getDataAndCheck();
  }

运行时错误日志

Performing hot restart...
Syncing files to device sdk gphone64 x86 64...
Restarted application in 3,201ms.
W/DynamiteModule(15758): Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found.
I/DynamiteModule(15758): Considering local module com.google.android.gms.providerinstaller.dynamite:0 and remote module com.google.android.gms.providerinstaller.dynamite:0
W/ProviderInstaller(15758): Failed to load providerinstaller module: No acceptable module com.google.android.gms.providerinstaller.dynamite found. Local version is 0 and remote version is 0.
W/ConnectivityManager.CallbackHandler(15758): callback not found for CALLBACK_AVAILABLE message
D/EGL_emulation(15758): app_time_stats: avg=58800.26ms min=766.16ms max=116834.36ms count=2
D/EGL_emulation(15758): app_time_stats: avg=1744.28ms min=1744.28ms max=1744.28ms count=1
I/flutter (15758): Email: abc123@gmail.com
I/flutter (15758): Password: 123456
I/flutter (15758): inside if
W/System  (15758): Ignoring header X-Firebase-Locale because its value was null.
W/System  (15758): Ignoring header X-Firebase-Locale because its value was null.
D/FirebaseAuth(15758): Notifying id token listeners about user ( NcSwfsdw7fc6ZFXH0ylSRMNonW63 ).
D/EGL_emulation(15758): app_time_stats: avg=3078.58ms min=3078.58ms max=3078.58ms count=1

问题分析与解决方案

从日志能看到Firebase已经成功登录(Notifying id token listeners about user),但跳转逻辑没执行,核心问题出在以下几点:

  1. catchError只捕获异常,未处理登录成功的情况
    signInWithEmailAndPassword成功时不会进入catchError分支,导致登录成功后没有触发跳转HomeScreen的逻辑,启动页一直停滞。

  2. Timer完全冗余,可能引发context状态问题
    已经用async/await处理了SharedPreference的异步操作,额外添加Timer不仅没必要,还可能导致context失效或逻辑延迟。

  3. SharedPreference实例重复创建
    每次调用sharedPreference()都会生成新实例,建议复用同一个实例以优化性能。

修改后的代码

void getDataAndCheck() async {
  final prefs = sharedPreference(); // 复用同一个SharedPreference实例
  bool emailPresent = await prefs.checkValuePresent('email');
  bool passwordPresent = await prefs.checkValuePresent('password');
  email = (await prefs.getCred('email')) ?? '';
  password = (await prefs.getCred('password')) ?? '';

  print('Email: $email\nPassword: $password');
  if (emailPresent && passwordPresent) {
    print('inside if');
    try {
      // 用try-catch覆盖登录成功和失败两种场景
      await firebaseAuth.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
      // 登录成功跳转主页
      print('Login success');
      Navigator.pushAndRemoveUntil(
        context,
        PageRouteBuilder(
          transitionDuration: const Duration(seconds: 1),
          transitionsBuilder: (context, animation, animationTime, child) {
            animation = CurvedAnimation(
              parent: animation,
              curve: Curves.fastLinearToSlowEaseIn,
            );
            return ScaleTransition(
              scale: animation,
              alignment: Alignment.center,
              child: child,
            );
          },
          pageBuilder: (context, animation, animationTime) {
            return const HomeScreen();
          },
        ),
        (route) => false,
      );
    } catch (errMsg) {
      print('inside catch error: ${errMsg.toString()}');
      // 登录失败,重置凭证并跳转登录页
      await prefs.reset();
      Navigator.pushReplacement(
        context,
        PageRouteBuilder(
          transitionDuration: const Duration(seconds: 1),
          transitionsBuilder: (context, animation, animationTime, child) {
            animation = CurvedAnimation(
              parent: animation,
              curve: Curves.fastLinearToSlowEaseIn,
            );
            return ScaleTransition(
              scale: animation,
              alignment: Alignment.center,
              child: child,
            );
          },
          pageBuilder: (context, animation, animationTime) {
            return const LoginOrSignUp();
          },
        ),
      );
    }
  } else {
    print('When email and password in not present');
    await prefs.reset();
    Navigator.pushReplacement(
      context,
      PageRouteBuilder(
        transitionDuration: const Duration(seconds: 1),
        transitionsBuilder: (context, animation, animationTime, child) {
          animation = CurvedAnimation(
            parent: animation,
            curve: Curves.fastLinearToSlowEaseIn,
          );
          return ScaleTransition(
            scale: animation,
            alignment: Alignment.center,
            child: child,
          );
        },
        pageBuilder: (context, animation, animationTime) {
          return const LoginOrSignUp();
        },
      ),
    );
  }
}

额外优化建议

  • 给启动页添加加载状态(比如CircularProgressIndicator),避免用户误以为App冻结。
  • 不要在SharedPreference中存储明文密码,这属于严重安全问题,建议改用Firebase自带的持久化登录(setPersistence),无需手动存储密码。

内容的提问来源于stack exchange,提问作者Mr Fin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:20:21