Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FutureBuilder runs twice

Tags:

flutter

dart

I have problems with FutureBuilder starting twice. First it fetch the data correctly, returning my StartScreen, then after few seconds, the StartScreen rebuilds and I noticed that the FutureBuilder fires again.

Here is my code and it's pretty simple, so I wonder what may the problem be?!?

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  FirebaseUser user;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getNewestlocation();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'APP',
      theme: buildTheme(),
      home: FutureBuilder<FirebaseUser>(
        future: Provider.of<AuthService>(context).getUser(),
        builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.error != null) {
              print('error');
              return Text(snapshot.error.toString());
            }
            user = snapshot.data;
            print('user here $user');
            return snapshot.hasData ? StartScreen(user) : LoginScreen();
          } else {
            return LoadingCircle();
          }
        },
      ),
    );
  }
}

Can anyone help me with this, please?

like image 423
i6x86 Avatar asked Nov 01 '19 18:11

i6x86


People also ask

Why is FutureBuilder called multiple times?

It's meant to represent any widget that triggers rebuilds like, for example, a user scrolling a ListView . The screen is split in two: Top: a StatelessWidget containing a FutureBuilder . It's fed a new Future that resolves to the current date in seconds.

How do you use future builder?

Show a constructor and parameters of Streambuilder. That is the way to utilize FutureBuilder in Flutter. You need to make a Future and pass it as the future argument. The snapshots of the Future will be passed to the builder function, in which you can decide the format to be shown depending on the current snapshot.


1 Answers

The future is firing again because you're creating it in the build method at the same time as the FutureBuilder.

From the FutureBuilder docs:

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateConfig, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.

So to prevent it from firing you'd have to do something like this:

    class _MyAppState extends State<MyApp> {
      Future<String> _myString;

      @override
      void initState() {
        super.initState();
        _myString = _fetchString();
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: FutureBuilder(
            future: _myString,
            builder: (context, snapshot) {
              // build page stuff...
            },
          ),
        );
      }
    }

    Future<String> _fetchString() async {
      print('running future function');
      await Future.delayed(Duration(seconds: 3));
      return 'potatoes';
    }

Note, to access a provider in initState() you have to set listen to false, as detailed in this answer.

like image 184
Alfred Jingle Avatar answered Sep 19 '22 13:09

Alfred Jingle