-1

I'm following FlutterFire getting started - https://firebase.flutter.dev/docs/overview. When I run the sample codes at initializing flutter fire, the FutureBuilder is invoked 3 times, the first for snapshot.connectionState is waiting, the second and the third for snapshot.connectionState is done. I don't understand the reason why FutureBuilder is called twice with the snapshot.connectionState == ConnectionState.done

Below is my code and exactly same with the example in the FlutterFire getting started page.

import 'package:flutter/material.dart';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';


void main() {
    WidgetsFlutterBinding.ensureInitialized();
    runApp(App());
}


class App extends StatefulWidget {

    @override
    _AppState createState() => _AppState();

}


class _AppState extends State<App> {

    final Future<FirebaseApp> _initialization = Firebase.initializeApp();

    @override
    Widget build(BuildContext context) {
        return FutureBuilder(
            future: _initialization,
            builder: (coontext, snapshot) {
                if (snapshot.hasError) {
                    Text("snapshot error. $snapshot");
                }

                if (snapshot.connectionState == ConnectionState.done) {
                    // this is printed twice!!
                    print("Initialize Firebase Done!!");
                    return MyHome();
                }

                return Loading();
            }
        );
    }

}


class Loading extends StatelessWidget {

    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            home: Scaffold(
                body: Center(
                    child: Container(
                        child: Text("Loading..."),
                    ),
                ),
            )
        );
    }

}


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 MaterialApp(
            home: Scaffold(
                body: Text('hello'),
            )
        );
    }

}
Noah
  • 417
  • 1
  • 5
  • 10
  • hi, please check link https://stackoverflow.com/a/50844913/5118503 – Sonu Kumar Jul 24 '21 at 21:42
  • @SonuKumar Thank you for the link. I tested FutureBuilder and I got to know whenerver `Widget build()` is called `builder` is also called in `FutureBuilder` with ConnectionState.done. I expected the `_initialization` (Future instance) triggers `builder` **only once** if iniitialization process finishes. – Jinhong Kim Jul 25 '21 at 06:35

1 Answers1

0

The code block below was run twice because the build method was called more than once and so it ran your FutureBuilder's builder callback more than once.

if (snapshot.connectionState == ConnectionState.done) {
  ...
}

From the documentation for the build method,

This method can potentially be called in every frame and should not have any side effects beyond building a widget.

https://api.flutter.dev/flutter/widgets/State/build.html

So your code should anticipate that the build method can be called at anytime.

Victor Eronmosele
  • 7,040
  • 2
  • 10
  • 33