Flutter如何在页面渲染前等待Future执行完成 避免冷启动闪登录页
解决方案
核心问题是AppModel初始化时currentUser默认值为null,首次build必然触发LoginPage渲染,等异步数据库查询完成更新状态才会跳转到HomePage,由此产生闪屏。可以通过以下两种方案解决:
方案1:提前初始化用户数据(最优)
你完全可以在main函数的异步阶段完成用户查询,直接给AppModel传入初始值,从根源避免初始currentUser为空的问题:
- 改造
AppModel构造函数,支持传入初始用户:
class AppModel extends ChangeNotifier { User? currentUser; // 新增构造参数接收初始用户 AppModel({User? initialUser}) : currentUser = initialUser; // 其余原有逻辑保持不变 }
- 修改
main函数,初始化Hive后提前查询用户:
void main() async { WidgetsFlutterBinding.ensureInitialized(); final document = await getApplicationDocumentsDirectory(); Hive.init(document.path); // 新增:提前查询本地用户 final userDao = UserDao(); final User? initialUser = await userDao.getCurrentUser(); // 替换为你实际的查用户方法 runApp( Phoenix( // 把初始用户传入MyApp child: MyApp(initialUser: initialUser), ), ); }
- 改造
MyApp,把初始用户传给AppModel:
class MyApp extends StatelessWidget { final User? initialUser; const MyApp({super.key, required this.initialUser}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ // 构造AppModel时传入初始值 ChangeNotifierProvider(create: (c) => AppModel(initialUser: initialUser)), Provider(create: (c) => UserDao()), // 其余provider保持不变 ], child: MaterialApp( title: '_', theme: ThemeData( primarySwatch: Colors.blue, ), home: AppScaffold() ), ); } }
改造完成后AppModel初始化时就已经拿到了本地存储的用户信息,首次build会直接渲染HomePage,不会出现LoginPage闪屏。AppScaffold的initState中的GetUserFromDB().run()逻辑可根据业务需求决定是否保留。
方案2:新增启动加载页过渡
如果不希望把用户查询逻辑放在main中,可以在路由判断前加一层启动屏过渡,加载完成后再跳转对应页面:
修改AppScaffold的build逻辑:
class _AppScaffoldState extends State<AppScaffold> { late final Future<User?> _loadUserFuture; @override initState() { super.initState(); // 初始化查询用户的Future _loadUserFuture = context.read<UserDao>().getCurrentUser(); } @override Widget build(BuildContext context) { return FutureBuilder<User?>( future: _loadUserFuture, builder: (context, snapshot) { // 加载阶段显示和应用开屏一致的启动页,用户无感知 if (snapshot.connectionState != ConnectionState.done) { return const SplashPage(); } // 加载完成后更新AppModel状态 final User? currentUser = snapshot.data; if (currentUser != null) { context.read<AppModel>().currentUser = currentUser; return const HomePage(title: 'HomePage'); } else { return const LoginPage(title: 'LoginPage'); } }, ); } }
该方案不需要修改上层初始化逻辑,加载阶段统一显示启动屏,同样不会出现LoginPage闪屏的问题。
内容的提问来源于stack exchange,提问作者Gob
相关产品推荐
相关产品推荐

