Flutter启动页用FutureBuilder判断登录跳转时报build中调用setState错误
问题根因
你触发的报错是因为在Widget构建执行过程中调用了导航跳转操作,FutureBuilder的builder回调属于build流程的一部分,这时候直接执行Navigator.pushReplacementNamed会触发页面状态变更,和当前正在执行的构建流程冲突,所以Flutter抛出了断言异常。
修复方案
只需要把跳转逻辑延后到当前帧构建完成之后再执行,用WidgetsBinding.instance.addPostFrameCallback包裹跳转逻辑即可,同时优化几个代码细节:
- 给FutureBuilder指定明确的泛型,避免类型转换风险
- 提前缓存Future,避免build重走时重复执行登录校验逻辑
- 补充错误场景的兜底处理
修复后完整代码如下:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Startup extends StatefulWidget { const Startup({Key? key}) : super(key: key); @override State<Startup> createState() => _StartupState(); } class _StartupState extends State<Startup> { // 提前缓存校验逻辑的Future,避免build重执行时重复调用 late final Future<String> _loginCheckFuture; @override void initState() { super.initState(); _loginCheckFuture = isLoggedIn(); } Future<String> isLoggedIn() async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString("key") != null ? "/MyTasks" : "/Login"; } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<String>( future: _loginCheckFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { // 跳转逻辑放到当前帧构建完成后执行,避免和build流程冲突 WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.of(context).pushReplacementNamed(snapshot.data!); }); } else if (snapshot.hasError) { // 读取失败时兜底跳转登录页,也可以根据需求显示错误提示 WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.of(context).pushReplacementNamed("/Login"); }); return Center(child: Text('加载失败: ${snapshot.error}')); } } // 校验过程显示加载动画 return const Center(child: CircularProgressIndicator()); }, ), ); } }
内容的提问来源于stack exchange,提问作者Ignacio Nacho Parravicini
相关产品推荐
相关产品推荐

