Flutter无状态启动页导航报错:访问已销毁Widget祖先不安全
问题:无状态启动页导航时触发已销毁Context报错
我实现了一个无状态的Splash Screen(启动页),用于检测用户登录状态:已登录则跳转主首页,未登录则跳转登录页。功能可正常运行,但出现以下报错:
E/flutter (21294): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe. E/flutter (21294): At this point the state of the widget's element tree is no longer stable. E/flutter (21294): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method. E/flutter (21294): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:4241:9) E/flutter (21294): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:4255:6) E/flutter (21294): #2 Element.findAncestorStateOfType (package:flutter/src/widgets/framework.dart:4322:12) E/flutter (21294): #3 Navigator.of (package:flutter/src/widgets/navigator.dart:2549:40) E/flutter (21294): #4 SplashScreen.build.<anonymous closure> (package:fbissalama/Screens/splashscreen.dart:20:18) E/flutter (21294): #5 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15) E/flutter (21294): #6 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19) E/flutter (21294): #7 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5) E/flutter (21294): #8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
相关代码
main.dart
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp( MultiProvider( providers: [ ChangeNotifierProvider<Following>( create: (BuildContext context) => Following(), ), ChangeNotifierProvider<ProviderController>( create: (BuildContext context) => ProviderController(), ), ChangeNotifierProvider<Verifying>( create: (BuildContext context) => Verifying(), ), //TODO //Add AuthController Here... ], child: MaterialApp( debugShowCheckedModeBanner: false, title: "Bissalama", onGenerateRoute: onGenerate, initialRoute: AppRoutes.splashScreenPage, routes: { AppRoutes.loginPage: (context) => const SignInScreen(), AppRoutes.splashScreenPage: (context) => const SplashScreen(), AppRoutes.mainHomePage: (context) => const MainHome(), AppRoutes.addJourneyPage: (context) => const AddJourneyPage(), AppRoutes.currentJourneyPage: (context) => const CurrentJourneyPage(), AppRoutes.favoriteJourneyPage: (context) => const FavoritePage(), AppRoutes.settingsPage: (context) => const SettingsPage(), AppRoutes.aboutPage: (context) => const AboutPage(), }, ), ), ); }
splashscreen.dart
class SplashScreen extends StatelessWidget { const SplashScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { Timer(const Duration(seconds: 1), () { final String? user = FirebaseAuth.instance.currentUser?.phoneNumber; final String? user1 = FirebaseAuth.instance.currentUser?.email; if (user1 != null || user != null) { Navigator.of(context).pushReplacementNamed('/home'); } else { Navigator.of(context).pushReplacementNamed('/'); } }); return Scaffold( body: Container( color: Colors.blueAccent, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Image.asset( AppAssets.busIcon, fit: BoxFit.fitHeight, ), ), const SizedBox( height: 20, ), Text( "Bissalama", style: GoogleFonts.lobster( textStyle: const TextStyle( color: Colors.white, fontSize: 30, fontWeight: FontWeight.bold), ), ), const SizedBox( height: 20, ), const SpinKitPouringHourGlassRefined( color: Colors.white, size: 50.0), ], ), ), ); } }
问题原因
你推测的结论正确:Timer延迟执行时,SplashScreen组件可能已经被从组件树中移除(比如页面快速切换、系统资源回收),此时使用已销毁的context调用Navigator就会触发该错误。
无状态组件下的解决方案
方案1:调用导航前检查Context状态
通过ModalRoute.of(context) != null判断当前context是否仍关联活跃路由,避免使用已销毁的context:
@override Widget build(BuildContext context) { Timer(const Duration(seconds: 1), () { final String? user = FirebaseAuth.instance.currentUser?.phoneNumber; final String? user1 = FirebaseAuth.instance.currentUser?.email; // 检查context是否仍处于活跃状态 if (ModalRoute.of(context) != null) { if (user1 != null || user != null) { Navigator.of(context).pushReplacementNamed('/home'); } else { Navigator.of(context).pushReplacementNamed('/'); } } }); // 原有UI代码不变 return Scaffold(...); }
方案2:使用PostFrameCallback替代Timer
WidgetsBinding.instance.addPostFrameCallback会在当前帧绘制完成后执行,结合Future.delayed模拟启动页展示时间,此时组件状态更稳定:
@override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { Future.delayed(const Duration(seconds: 1), () { final String? user = FirebaseAuth.instance.currentUser?.phoneNumber; final String? user1 = FirebaseAuth.instance.currentUser?.email; if (ModalRoute.of(context) != null) { if (user1 != null || user != null) { Navigator.of(context).pushReplacementNamed('/home'); } else { Navigator.of(context).pushReplacementNamed('/'); } } }); }); // 原有UI代码不变 return Scaffold(...); }
方案3:改用StatefulWidget(可选)
如果后续需要更多生命周期逻辑,StatefulWidget可以直接通过mounted属性判断组件是否存活,代码更直观:
class SplashScreen extends StatefulWidget { const SplashScreen({Key? key}) : super(key: key); @override State<SplashScreen> createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { @override void initState() { super.initState(); Future.delayed(const Duration(seconds: 1), () { final String? user = FirebaseAuth.instance.currentUser?.phoneNumber; final String? user1 = FirebaseAuth.instance.currentUser?.email; // 直接判断组件是否存活 if (mounted) { if (user1 != null || user != null) { Navigator.of(context).pushReplacementNamed('/home'); } else { Navigator.of(context).pushReplacementNamed('/'); } } }); } @override Widget build(BuildContext context) { // 原有UI代码不变 return Scaffold(...); } }
内容的提问来源于stack exchange,提问作者saad tabban
相关产品推荐
相关产品推荐

