flutter how to use future async method in init state

6,749

The initState method is synchronous by design. Rather than creating the FutureBuilder widget in the initState method, you could return the FutureBuilder widget in the overridden build method. Feel free to take a look at the documentation for the FutureBuilder widget here for an example of how this could work.

It looks like there is also an issue with the code in the setState callback function. You probably want to replace imgList = widget.imageList as List<String>; with imgList = snapshot.data as List<String>; in order to use the data from the completed future.

It looks like there is also an issue with the build method not returning a widget in all the cases. I have taken your updated code sample and modified it as below:

import 'package:flutter/material.dart';

class BottomSheetWidget extends StatefulWidget {
  BottomSheetWidget({Key key, this.name, this.imageList}) : super(key: key);

  final String name;

  final Future<List<String>> imageList;

  @override
  _BottomSheetWidgetState createState() => _BottomSheetWidgetState();
}

class _BottomSheetWidgetState extends State<BottomSheetWidget> {
  int _current = 0;

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<String>>(
      future: widget.imageList,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          final imgList = snapshot.data;

          return Container(
            decoration: BoxDecoration(
              color: Colors.red,
              borderRadius: BorderRadius.circular(25),
            ),
            height: MediaQuery.of(context).size.height * 0.85,
            width: MediaQuery.of(context).size.width,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 15),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: <Widget>[
                      CarouselSlider(
                        items: imgList.map(
                          (item) {
                            return Container(
                              child: Container(
                                margin: EdgeInsets.all(5.0),
                                child: ClipRRect(
                                  borderRadius:
                                      BorderRadius.all(Radius.circular(5.0)),
                                  child: Stack(
                                    children: <Widget>[
                                      Image.network(
                                        item,
                                        fit: BoxFit.cover,
                                        height: 1000.0,
                                        width: 1000.0,
                                      ),
                                      Positioned(
                                        bottom: 0.0,
                                        left: 0.0,
                                        right: 0.0,
                                        child: Container(
                                          decoration: BoxDecoration(
                                            gradient: LinearGradient(
                                              colors: [
                                                Color.fromARGB(200, 0, 0, 0),
                                                Color.fromARGB(0, 0, 0, 0)
                                              ],
                                              begin: Alignment.bottomCenter,
                                              end: Alignment.topCenter,
                                            ),
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            );
                          },
                        ).toList(),
                        options: CarouselOptions(
                          enlargeCenterPage: true,
                          enlargeStrategy: CenterPageEnlargeStrategy.height,
                          height: MediaQuery.of(context).size.height - 500,
                          aspectRatio: 2.0,
                          onPageChanged: (index, reason) {
                            setState(() {
                              _current = index;
                            });
                          },
                        ),
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: imgList.map((url) {
                          return Container(
                            width: 8.0,
                            height: 8.0,
                            margin: EdgeInsets.symmetric(
                                vertical: 10.0, horizontal: 2.0),
                            decoration: BoxDecoration(
                              shape: BoxShape.circle,
                              color: _current == imgList.indexOf(url)
                                  ? Color.fromRGBO(0, 0, 0, 0.9)
                                  : Color.fromRGBO(0, 0, 0, 0.4),
                            ),
                          );
                        }).toList(),
                      ),
                      Text(
                        widget.name,
                        style: TextStyle(
                          fontSize: 30,
                          color: Colors.white,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      Text(
                        "United Kingdom",
                        style: TextStyle(
                          fontSize: 18,
                          color: Colors.white,
                        ),
                      ),
                    ],
                  ),
                )
              ],
            ),
          );
        } else {
          return CircularProgressIndicator();
        }
      },
    );
  }
}
Share:
6,749
iKreateCode
Author by

iKreateCode

Updated on December 22, 2022

Comments

  • iKreateCode
    iKreateCode over 1 year

    When the screen loads i want the init state to fill the List with Future<List> that is passed through the stateful widget. However since its a future, my method will crash and not work.

    My code

      @override
      void initState() async {
        FutureBuilder(
          future: widget.imageList,
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                print('NONE');
                break;
              case ConnectionState.active:
              case ConnectionState.waiting:
                print("WAITING");
                break;
              case ConnectionState.done:
                print("DONE");
                setState(() {
                  imgList = widget.imageList as List<String>;
                });
                break;
            }
          },
        );
        super.initState();
      }
    

    Error Produced

    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    _BottomSheetWidgetState.initState() returned a Future.
    The relevant error-causing widget was
        MaterialApp 
    
    

    Stateful widget where the list is passed through

    List<String> imgList = List<String>();
    
    class BottomSheetWidget extends StatefulWidget {
      BottomSheetWidget({Key key, this.name, this.imageList}) : super(key: key);
    
      String name;
      Future<List<String>> imageList;
    

    Whole edited code:

    List<String> imgList = List<String>();
    
    class BottomSheetWidget extends StatefulWidget {
      BottomSheetWidget({Key key, this.name, this.imageList}) : super(key: key);
    
      String name;
      Future<List<String>> imageList;
    
      @override
      _BottomSheetWidgetState createState() => _BottomSheetWidgetState();
    }
    
    class _BottomSheetWidgetState extends State<BottomSheetWidget> {
      int _current = 0;
    
      final List<Widget> imageSliders = imgList
          .map((item) => Container(
                child: Container(
                  margin: EdgeInsets.all(5.0),
                  child: ClipRRect(
                      borderRadius: BorderRadius.all(Radius.circular(5.0)),
                      child: Stack(
                        children: <Widget>[
                          Image.network(item,
                              fit: BoxFit.cover, height: 1000.0, width: 1000.0),
                          Positioned(
                            bottom: 0.0,
                            left: 0.0,
                            right: 0.0,
                            child: Container(
                              decoration: BoxDecoration(
                                gradient: LinearGradient(
                                  colors: [
                                    Color.fromARGB(200, 0, 0, 0),
                                    Color.fromARGB(0, 0, 0, 0)
                                  ],
                                  begin: Alignment.bottomCenter,
                                  end: Alignment.topCenter,
                                ),
                              ),
                            ),
                          ),
                        ],
                      )),
                ),
              ))
          .toList();
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
          future: widget.imageList,
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                print('NONE');
                break;
              case ConnectionState.active:
              case ConnectionState.waiting:
                print("WAITING");
                break;
              case ConnectionState.done:
                print("DONNE");
                setState(() async {
                    imgList = snapshot.data as List<String>;
    
                });
    
                return Container(
                  decoration: BoxDecoration(
                    color: Colors.red,
                    borderRadius: BorderRadius.circular(25),
                  ),
                  height: MediaQuery.of(context).size.height * 0.85,
                  width: MediaQuery.of(context).size.width,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.symmetric(horizontal: 15),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: <Widget>[
                            CarouselSlider(
                              items: imageSliders,
                              options: CarouselOptions(
                                  enlargeCenterPage: true,
                                  enlargeStrategy: CenterPageEnlargeStrategy.height,
                                  height: MediaQuery.of(context).size.height - 500,
                                  aspectRatio: 2.0,
                                  onPageChanged: (index, reason) {
                                    setState(() {
                                      _current = index;
                                    });
                                  }),
                            ),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: imgList.map((url) {
                                int index = imgList.indexOf(url);
                                return Container(
                                  width: 8.0,
                                  height: 8.0,
                                  margin: EdgeInsets.symmetric(
                                      vertical: 10.0, horizontal: 2.0),
                                  decoration: BoxDecoration(
                                    shape: BoxShape.circle,
                                    color: _current == index
                                        ? Color.fromRGBO(0, 0, 0, 0.9)
                                        : Color.fromRGBO(0, 0, 0, 0.4),
                                  ),
                                );
                              }).toList(),
                            ),
                            Text(widget.name,
                                style: TextStyle(
                                    fontSize: 30,
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold)),
                            Text("United Kingdom",
                                style: TextStyle(
                                  fontSize: 18,
                                  color: Colors.white,
                                )),
                          ],
                        ),
                      )
                    ],
                  ),
                );
                break;
            }
          },
        );
      }
    }
    

    New error from console:

    flutter: WAITING
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    A build function returned null.
    The relevant error-causing widget was
        FutureBuilder<List<String>> 
    lib/common_widget/bottom_sheet.dart:54
    ════════════════════════════════════════════════════════════════════════════════
    flutter: DONNE
    
    ════════ Exception caught by widgets library ═══════════════════════════════════
    setState() callback argument returned a Future.
    The relevant error-causing widget was
        FutureBuilder<List<String>> 
    lib/common_widget/bottom_sheet.dart:54
    ════════════════════════════════════════════════════════════════════════════════
    
    • Jitesh Mohite
      Jitesh Mohite almost 4 years
      this should be done inside build method, not in initt
    • iKreateCode
      iKreateCode almost 4 years
      I am still learning flutter and classed as a beginner. The only reason i put it inside init state was because i want that to run first before anything else. So if i were to include it inside the build would it still run first?
    • tnc1997
      tnc1997 almost 4 years
      The FutureBuilder widget provides you with a snapshot which contains details of whether the future has completed amongst others. You could use this to check if the future has completed before rendering other widgets that depend on the result of the future. Any widgets returned from within the builder callback function of the FutureBuilder will be created after the FutureBuilder has been created.
  • iKreateCode
    iKreateCode almost 4 years
    I think using that i have managed to get it somewhat working before i can accept your answer i am getting this error within the done case. type 'Future<List<String>>' is not a subtype of type 'List<String>' in type cast. I believe this happens in the set state
  • tnc1997
    tnc1997 almost 4 years
    Would you be able to post an updated code sample of the BottomSheetWidget and the _BottomSheetWidgetState?
  • tnc1997
    tnc1997 almost 4 years
    Perfect, I have updated my answer based on the updated code sample.
  • iKreateCode
    iKreateCode almost 4 years
    Hmmm, having tried that i still get an error, i updated my code above
  • tnc1997
    tnc1997 almost 4 years
    Apologies, I missed another issue which is your build method not returning a widget in all the cases.