Flutter中Firebase.initializeApp的FutureBuilder两次触发ConnectionState.done
问题原因
你遇到的ConnectionState.done触发两次的问题,由两个常见原因导致:
- 组件树结构设计错误:你当前代码里
Loading和MyHome两个分支都各自返回独立的MaterialApp实例。当Future完成后,Flutter需要替换整棵MaterialApp子树,这个过程会触发上层_AppState重新执行build方法,此时_initialization已经是完成状态,会再次命中done分支产生第二次打印。 - 小概率的Firebase Core内部逻辑:FlutterFire的初始化方法完成后,内部会同步更新一次全局实例状态,也可能触发FutureBuilder的回调重复执行。
另外你代码的错误分支没有加return语句,属于隐藏bug,需要同步修复。
修复方案
第一步:调整顶层组件结构,把MaterialApp提到FutureBuilder外层
修改_AppState的代码如下:
class _AppState extends State<App> { final Future<FirebaseApp> _initialization = Firebase.initializeApp(); @override Widget build(BuildContext context) { return MaterialApp( home: FutureBuilder( future: _initialization, builder: (context, snapshot) { if (snapshot.hasError) { // 补充return逻辑 return Scaffold( body: Center(child: Text("初始化出错:${snapshot.error}")) ); } if (snapshot.connectionState == ConnectionState.done) { print("Initialize Firebase Done!!"); return MyHome(); } return Loading(); }, ), ); } }
第二步:移除子组件里多余的MaterialApp
修改Loading组件代码,去掉外层MaterialApp包裹:
class Loading extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text("Loading..."), ), ); } }
修改MyHome组件代码,同样去掉外层MaterialApp:
class MyHome extends StatefulWidget { @override _MyHomeState createState() => _MyHomeState(); } class _MyHomeState extends State { @override void initState() { FirebaseAuth .instance .idTokenChanges() .listen((User? user) { if (user == null) { print('User is signed out'); } else { print('User is signed in!.' + user.displayName!); } }); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: Text('hello'), ); } }
额外说明
调整完成后绝大多数场景下只会触发一次done分支的打印。如果仍有偶发的两次打印也无需担心,因为你已经将初始化Future缓存到了State中,不会重复执行Firebase初始化逻辑,只是build方法的正常重入,没有性能问题和副作用。
内容的提问来源于stack exchange,提问作者Jinhong Kim
相关产品推荐
相关产品推荐

