6

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

2 Answers 2

12

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.

Sign up to request clarification or add additional context in comments.

2 Comments

just tried your solution too and the error was this one "MappedListIterable<CardapioLista, Map<String, dynamic>>' has no instance method '[]'"
print snapshot.data and tell me what you see
3

I'm not sure how your widget tree looks like, but I'm assuming ListView is being built simultaneously with pegaDados. What you're looking for is a FutureBuilder:


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

  return items.map((item) => item.toMap());
}

...
FutureBuilder<dynamic>(
  future: pegaDados(),
  builder: (BuilderContext context, AsyncSnapshot snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return Text('Uninitialized');
      case ConnectionState.active:
      case ConnectionState.waiting:
        return Text('Awaiting result...');
      case ConnectionState.done:

        if (snapshot.hasError)
          throw snapshot.error;

        //
        // Place here your ListView.
        //
    }
    return null; // unreachable
  }

9 Comments

what i can replace the 'BuilderContext' with? My classes are as StatelessWidgets
here is the error ''The argument type 'StatelessWidget Function(CardapioList, AsyncSnapshot<dynamic>)' can't be assigned to the parameter type 'Widget Function(BuildContext, AsyncSnapshot<dynamic>)''
Each widget whether it's stateful or stateless has a build method with context, so just pass this context to the FutureBuilder.
A red screen and yellow letters appeared "a build function returned null"
@VitorAraújo you probably forgot to return.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.