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

Flutter登录状态重启时出现已卸载Widget状态上下文错误求助

登录状态判断与页面跳转错误分析及解决

问题背景

预期逻辑:

  • 保持登录状态重启应用,用户直接进入BottomNav页面
  • 退出登录后重启,用户先看到Splash启动页

添加Splash后,已登录状态下重启应用出现以下错误:
调试控制台错误

已发生异常。FlutterError(此Widget已被卸载,因此State不再拥有上下文(应视为失效)。请考虑在"dispose"期间取消所有活跃任务,或使用"mounted" getter判断State是否仍处于活跃状态。)

相关代码

main.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:recipe_collector/Authen/InfoPage.dart';
import 'package:recipe_collector/Authen/email_Login.dart';
import 'package:recipe_collector/splash_screen.dart';
import 'All Recipes/viewRecipe.dart';
import 'BottomNavigationBar.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:recipe_collector/globalVariable.dart' as global;
import 'Profile/Profile.dart';
import 'globalVariable.dart';

Future main() async {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<FirebaseUser>(
        future: FirebaseAuth.instance.currentUser(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            FirebaseUser? user = snapshot.data;
            if (user != null) {
              getCurrentUser();
            }
            return MaterialApp(
              debugShowCheckedModeBanner: false,
              title: 'Recipes Collector ',
              initialRoute: "/",
              home: BottomNav(),
            );
          } else {
            return Splash();
          }
        });
  }
}

Splash.dart

import 'dart:async';
import 'dart:ui';
import 'package:google_fonts/google_fonts.dart';
import 'package:splashscreen/splashscreen.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:liquid_swipe/liquid_swipe.dart';
import 'Authen/InfoPage.dart';

class Splash extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SplashScreen(
        seconds: 3,
        navigateAfterSeconds:  MyliquidSwipe(),
        styleTextUnderTheLoader:  TextStyle(),
        title:  Text.rich(
          textAlign: TextAlign.center,
          TextSpan(
            children: [
              TextSpan(
                  text: 'Access Your Recipes Collection',
                  style: TextStyle(
                    fontSize: 18,
                    color: Color.fromARGB(
                      255,
                      230,
                      200,
                      160,
                    ),
                    letterSpacing: 1,
                  )),
              TextSpan(
                  text: '\nAnytime &amp; Anywhere',
                  style: TextStyle(
                    letterSpacing: 2,
                    fontSize: 23,
                    fontWeight: FontWeight.w600,
                    height: 1.5,
                    color: Color.fromARGB(255, 230, 200, 160),
                  )),
              TextSpan(
                  text: '\nJust at Your Fingertip!',
                  style: TextStyle(
                      letterSpacing: 1,
                      fontSize: 18,
                      color: Color.fromARGB(255, 230, 200, 160)))
            ],
          ),
        ),
        image: Image.asset("assets/Logo.png"),
        photoSize: 150.0,
         imageBackground: AssetImage("assets/IntroPage/Create Your Own Recipe.png"),
        loaderColor: Color.fromARGB(255, 230, 200, 160),
      ),
    );
  }
}

错误成因

  1. 多MaterialApp实例冲突:MyApp根据登录状态返回不同的MaterialApp,已登录时返回的MaterialApp会替换掉Splash中的MaterialApp,但Splash内部的SplashScreen仍在执行3秒后的导航任务,试图在已被卸载的上下文里跳转,导致错误。
  2. 异步判断的短暂状态切换:FutureBuilder获取用户状态是异步操作,在结果返回前会短暂进入else分支渲染Splash,之后切换到已登录页面,此时Splash的导航任务未被取消,继续执行引发上下文失效。
  3. build方法内执行异步操作:在MyApp的build方法中直接调用getCurrentUser(),build方法是同步执行的,异步操作可能在Widget未稳定完成渲染时执行,引发上下文相关问题。

解决方法

1. 全局仅保留一个MaterialApp

将MaterialApp提升到FutureBuilder外层,确保整个应用只有一个导航上下文,避免多实例冲突:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
// 其他导入保持不变

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(); // 必须初始化Firebase
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Recipes Collector ',
      home: FutureBuilder<User?>(
        // 用authStateChanges().first替代currentUser(),状态监听更可靠
        future: FirebaseAuth.instance.authStateChanges().first,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            // 显示过渡加载页,避免短暂闪显Splash
            return Scaffold(body: Center(child: CircularProgressIndicator(color: Color.fromARGB(255, 230, 200, 160))));
          }
          
          if (snapshot.hasData && snapshot.data != null) {
            // 用Future.microtask延迟执行异步操作,避免在build中直接调用
            Future.microtask(() => getCurrentUser());
            return BottomNav();
          } else {
            return Splash();
          }
        },
      ),
    );
  }
}

2. 移除Splash中的MaterialApp

因为外层已经有全局的MaterialApp,Splash只需返回SplashScreen即可:

import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';
import 'Authen/InfoPage.dart';

class Splash extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SplashScreen(
      seconds: 3,
      navigateAfterSeconds: MyliquidSwipe(),
      styleTextUnderTheLoader: TextStyle(),
      title: Text.rich(
        textAlign: TextAlign.center,
        TextSpan(
          children: [
            TextSpan(
                text: 'Access Your Recipes Collection',
                style: TextStyle(
                  fontSize: 18,
                  color: Color.fromARGB(255, 230, 200, 160),
                  letterSpacing: 1,
                )),
            TextSpan(
                text: '\nAnytime & Anywhere',
                style: TextStyle(
                  letterSpacing: 2,
                  fontSize: 23,
                  fontWeight: FontWeight.w600,
                  height: 1.5,
                  color: Color.fromARGB(255, 230, 200, 160),
                )),
            TextSpan(
                text: '\nJust at Your Fingertip!',
                style: TextStyle(
                    letterSpacing: 1,
                    fontSize: 18,
                    color: Color.fromARGB(255, 230, 200, 160)))
          ],
        ),
      ),
      image: Image.asset("assets/Logo.png"),
      photoSize: 150.0,
      imageBackground: AssetImage("assets/IntroPage/Create Your Own Recipe.png"),
      loaderColor: Color.fromARGB(255, 230, 200, 160),
    );
  }
}

3. 优化异步操作执行时机

如果getCurrentUser()内部包含异步操作,确保在执行时判断上下文是否活跃(如果是在StatefulWidget中调用),或者用Future.microtask延迟执行,避免干扰Widget渲染流程。

额外注意事项

  • 确保Firebase初始化完成:在main方法中必须调用WidgetsFlutterBinding.ensureInitialized()和await Firebase.initializeApp(),否则Firebase相关操作会报错。
  • Firebase版本兼容:新版本Firebase Auth中currentUser()已被authStateChanges()替代,FirebaseUser类也改为User,需根据实际版本调整代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:40:06