Mandeep
Mandeep

Reputation: 355

How to use InitState when using Future Function and Future builder in flutter

I am facing a problem in Flutter. I am not use to using Future Functions that efficiently. I am trying to get a value from Future function in InitSate of stateful class and later using the return value in Future Builder. However, at the moment when i do l_orders = await xyz(); or l_orders = xyz(); inside initstate it does not work My screen does not load its always shows only CircularProgressIndicator.

However, when I move l_orders = xyz(); outside InitState than everything works. I want to do this inside InitState as later I want to use setState aswell. So this is my first step of implementation before moving to setState part.

Any sort of help is highly appreciated. Thank You

my codes are -

class _OrderScreenState extends State<OrderScreen> {

  Future<String> xyz() async{
    return("processing ....");
  }

  @override
  Widget build (BuildContext context) {
    final orders = Provider.of<Orders>(context);
    var l_orders;

    @override
    void initState() async {
      super.initState();
      l_orders = await xyz();
    }


    return WillPopScope(
      onWillPop: () async {
        return false;
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Orders'),
          actions: <Widget>[Padding(
            padding: const EdgeInsets.all(8.0),
            //child: IconButton(icon:Icon(Icons.home, size: 30,),onPressed: (){Navigator.of(context).pushNamed(HomePage.routeName);},),
          ),],
        ),
        body: FutureBuilder(
          future: l_orders,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (!snapshot.hasData) {
              // while data is loading:
              return Center(
                child: CircularProgressIndicator(backgroundColor: Colors.red,valueColor: new AlwaysStoppedAnimation<Color>(Colors.blue)),
              );
            } else {
              // data loaded:
             return Text("Test");
            }
          },
        ),

        floatingActionButton: FloatingActionButton(

          onPressed: (){Navigator.of(context).pushNamed(HomePage.routeName);},
          child: Icon(Icons.home,size: 40,),
          //backgroundColor: Colors.green,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
       ),
    );
  }
} 

Upvotes: 1

Views: 5178

Answers (2)

caiohamamura
caiohamamura

Reputation: 2738

You don't need FutureBuilder if you are inside a StatefulWidget:

@override
void initState() {
  xyz().then((value) {
    setState(() {
      l_orders = value;
    });
  });
  super.initState();
}

Then you can build it like this:

// Scaffold body
body: l_orders == null ? 
  CircularProgressIndicator() :
  Text('l_orders received!')

With FutureBuilder you don't even need the widget to be StatefulWidget. I only use StatefulWidget if I need to call setState to force it to rebuild. If I never use setState within a StatefulWidget, then there's no need to keep it stateful.

Upvotes: 0

Christopher Moore
Christopher Moore

Reputation: 17143

You're not passing a Future to FutureBuilder. l_orders is actually a String because you're awaiting it in initState. Do not use await in initState even though static analysis may allow you to.

initState should be the following:

@override
void initState() {
  super.initState();
  l_orders = xyz();
}

Additionally, all of your members and your initState declaration are in build. Move them outside of build into the body of your class.

class _OrderScreenState extends State<OrderScreen> {
  var l_orders;

  @override
  void initState() {
    super.initState();
    l_orders = xyz();
  }

  Future<String> xyz() async{
    return("processing ....");
  }

  @override
  Widget build (BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        return false;
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Orders'),
          actions: <Widget>[Padding(
            padding: const EdgeInsets.all(8.0),
            //child: IconButton(icon:Icon(Icons.home, size: 30,),onPressed: (){Navigator.of(context).pushNamed(HomePage.routeName);},),
          ),],
        ),
        body: FutureBuilder(
          future: l_orders,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (!snapshot.hasData) {
              // while data is loading:
              return Center(
                child: CircularProgressIndicator(backgroundColor: Colors.red,valueColor: new AlwaysStoppedAnimation<Color>(Colors.blue)),
              );
            } else {
              // data loaded:
             return Text("Test");
            }
          },
        ),

        floatingActionButton: FloatingActionButton(

          onPressed: (){print('test');},
          child: Icon(Icons.home,size: 40,),
          //backgroundColor: Colors.green,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
       ),
    );
  }
} 

Giving l_orders a static type would help you find these errors at compile-time. Instead of using the dynamic var l_orders;, use Future l_orders; or Future<String> l_orders;. Additionally, pay attention to all static analysis warning. Just because they're not errors doesn't mean they don't matter.

Upvotes: 3

Related Questions