Search code examples
asynchronousflutterandroid-sqlite

Flutter how to get data from async function


I am having extreme difficulty in handling this. I call an async function that will get some info from SQLite but I can't seem to get it. It just renders a empty screen in which should be a listview.

List allItems = new List();

Future<void> pegaDados() async {
    var itens = await geraCardapio();
      
    for (var i = 0; i < itens.length; i++) {
        print((itens[i].toMap()));
        allItems.add(itens[i].toMap());
    }
}

print(pegaDados());

return ListView.builder(
    itemCount: allItems.length,
    itemBuilder: (context, index) {
        return ListTile(
            leading: Image.asset("assets/"+ allItems[index]['imagem'], fit: BoxFit.contain,),
            title: Text(allItems[index]['pedido']),
            trailing: Text(allItems[index]['valor']),
        );
    },
);

Thank you very much.

I managed to get the solution, thanks to both people who answered the question (using both solutions I managed to get this little frankenstein)

Future<dynamic> pegaDados() async {
    var allItems = await geraCardapio();

    return allItems.map((allItems) => allItems.toMap());
}

return FutureBuilder(
    future: pegaDados(),
    builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
            print(snapshot.data);
            var objeto = [];

            for (var i in snapshot.data) {
                objeto.add(i);
            }
              
            print(objeto);
            return Container(
                child: ListView.builder(
                itemCount: objeto.length,
                itemBuilder: (context, index) {
                    return ListTile(
                        leading: Image.asset("assets/"+ objeto[index]['imagem'], fit: BoxFit.contain),
                        title: Text(objeto[index]['pedido']),
                        trailing: Text(objeto[index]['valor'].toString()),
                    );
                },
            ),
        );
    } else if (snapshot.hasError) {
        throw snapshot.error;
    } else {
        return Center(child: CircularProgressIndicator());
    }
});

thanks to [Mohammad Assem Nasser][1] and [Eliya Cohen][2] for the help!

  [1]: https://stackoverflow.com/users/11542171/mohammad-assem-nasser
  [2]: https://stackoverflow.com/users/1860540/eliya-cohen

Solution

  • You should first understand what is Future operations (Future function in your case). Future operations are the operations which take time to perform and return the result later. To handle this problem, we use Asynchronous functions.

    Asynchronous Function let your program continue other operations while the current operation is being performed. Dart uses Future objects (Futures) to represent the results of asynchronous operations. To handle these operations, we can use async/await, but it is not possible to integrate async and await on widgets. So it is quite tricky to handle futures in widgets. To solve this problem flutter provided a widget called FutureBuilder.

    In FutureBuilder, it calls the Future function to wait for the result, and as soon as it produces the result it calls the builder function where we build the widget.

    Here is how it should be:

    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> {
      List allItems = new List();
    
      Future<List> pegaDados() async{
        var items = await geraCardapio(); // TODO: Add this function to this class
    
        for (var i = 0; i < items.length; i++) {
          print((items[i].toMap()));
          allItems.add(items[i].toMap());
        }
      return items;
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(title: Text('Demo')),
          body: FutureBuilder(
            future: pegaDados(),
            builder: (context, snapshot){
              if(snapshot.connectionState == ConnectionState.done){
                return Container(
                    child: ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      leading: Image.asset("assets/"+ snapshot.data[index]['imagem'], fit: BoxFit.contain,),
                      title: Text(snapshot.data[index]['pedido']),
                      trailing: Text(snapshot.data[index]['valor']),
                    );
                  },
                    ),
                );
              }
              else if(snapshot.hasError){
                throw snapshot.error;
              }
              else{
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
        );
      }
    }
    

    Here is the link to a short video that will explain FutureBuilder in a concise way.