如何为集成Routemaster的Flutter应用添加启动屏并解决闪屏问题?
解决方案:解决启动闪屏问题并实现正确的登录状态路由跳转
问题根源
你的代码中,当Firebase Auth返回已登录用户时,会异步调用getData获取用户数据,但routesBuilder会立刻执行——此时userModel还未加载完成,因此会先返回未登录路由(显示登录页),等异步操作完成后才更新状态切换到首页,这就是启动时闪登录页的核心原因。
下面是修正后的完整方案:
1. 创建启动屏页面
先实现一个展示Logo和加载状态的启动屏,替换成你自己的资源即可:
import 'package:flutter/material.dart'; class SplashScreen extends StatelessWidget { const SplashScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 替换为你的应用Logo路径 Image.asset( 'assets/app_logo.png', width: 140, height: 140, ), const SizedBox(height: 30), const CircularProgressIndicator(strokeWidth: 3), ], ), ), ); } }
2. 优化状态监听逻辑(RiverProvider)
在auth_controller.dart中添加一个组合Provider,统一监听Firebase Auth状态和用户数据加载过程,避免状态不一致:
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../models/user_model.dart'; // 原有的authStateChangeProvider保持不变 final authStateChangeProvider = StreamProvider<User?>((ref) { return FirebaseAuth.instance.authStateChanges(); }); // 新增:组合监听Auth状态+用户数据加载 final authStateWithUserProvider = FutureProvider<UserModel?>((ref) async { // 先等待Auth状态返回 final authUser = await ref.watch(authStateChangeProvider.future); if (authUser == null) return null; // 再加载用户详细数据(复用你原有的getUserData方法) return ref.watch(authControllerProvider.notifier) .getUserData(authUser.uid) .first; });
3. 修改main.dart的路由逻辑
简化MyApp组件,通过新的组合Provider监听状态,确保在加载完成前始终显示启动屏:
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:my_first_flutter_app/core/common/error_text.dart'; import 'package:my_first_flutter_app/features/auth/controller/auth_controller.dart'; import 'package:my_first_flutter_app/firebase_options.dart'; import 'package:my_first_flutter_app/models/user_model.dart'; import 'package:my_first_flutter_app/router.dart'; import 'package:my_first_flutter_app/theme/pallete.dart'; import 'package:my_first_flutter_app/screens/splash_screen.dart'; // 导入启动屏 import 'package:routemaster/routemaster.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp( const ProviderScope( child: MyApp(), ), ); } class MyApp extends ConsumerWidget { const MyApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return MaterialApp.router( debugShowCheckedModeBanner: false, title: 'My Flutter App', theme: ref.watch(themeNotifierProvider), routerDelegate: RoutemasterDelegate( routesBuilder: (context) { // 监听完整的登录状态流程 return ref.watch(authStateWithUserProvider).when( // 加载中:始终返回启动屏路由 loading: () => RouteMap(routes: { '/': (_) => const MaterialPage(child: SplashScreen()), }), // 出错:显示错误页面 error: (error, stackTrace) => RouteMap(routes: { '/': (_) => MaterialPage(child: ErrorText(error: error.toString())), }), // 状态确定:根据用户数据跳转对应页面 data: (userModel) { if (userModel != null) { // 更新全局用户状态 ref.read(userProvider.notifier).update((_) => userModel); return loggedInRoute; } else { return loggedOutRoute; } }, ); }, ), routeInformationParser: const RoutemasterParser(), ); } }
4. 保留原router.dart不变
你的router.dart可以继续使用,无需修改:
import 'package:flutter/material.dart'; import 'package:my_first_flutter_app/features/auth/screen/login_screen.dart'; import 'package:my_first_flutter_app/features/home/screens/home_screen.dart'; import 'package:routemaster/routemaster.dart'; final loggedOutRoute = RouteMap(routes: { '/': (_) => const MaterialPage(child: LoginScreen()), }); final loggedInRoute = RouteMap(routes: { '/': (_) => const MaterialPage(child: HomeScreen()), });
核心改进说明
- 彻底避免了
routesBuilder中执行异步操作导致的路由提前跳转问题,确保在用户状态完全确定前,始终显示启动屏。 - 通过组合Provider统一管理Auth状态和用户数据加载流程,消除了状态不一致的可能性。
- 启动屏会持续显示到Firebase Auth状态返回、用户数据加载完成,完美解决网络慢时的闪屏问题。
内容的提问来源于stack exchange,提问作者AvestaChang
相关产品推荐
相关产品推荐

