Как показать результат асинхронной функции в списке

Я пытаюсь создать список, чтобы отображать некоторые события с их соответствующими пользователями, но список создается до завершения метода, а затем получается пустой список ...

Я пробовал это, но проблема все еще сохраняется:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:project/Methods.dart';
import 'package:project/Views/CadastroUsuario.dart';
import 'package:project/classes/eventos.dart';

class ListagemEventos extends StatefulWidget {
  @override
  ListagemEventosState createState() => new ListagemEventosState();
}

class ListagemEventosState extends State<ListagemEventos> {
  @override
  void initState() {
    super.initState();
  }

  Future<List<Event>> getEvents() async {
    CollectionReference eventsDoc = Firestore.instance.collection("events");
    return await eventsDoc.getDocuments().then((snapshot) { 
       List<Event> events = new List<Event>();
       snapshot.documents.forEach((doc) async {
          Event event = new Event();  
          String id;         

          event.description      = doc["description"];
          event.city             = doc["city"];
          event.state            = doc["state"];
          event.location         = doc["location"];
          event.date             = doc["date"];
          event.placesAvailable  = doc["placesAvailable"];
          event.totalPlaces      = doc["placesTotal"];

          id = doc["userId"];
          event.owner = new UserOwner();

          CollectionReference eventsDoc = Firestore.instance.collection("users");
          event.owner = await eventsDoc.document(id).get().then((doc) {
            UserOwner userOwner = new UserOwner();
            userOwner.userid = id;
            userOwner.name   = doc["name"];
            userOwner.phone  = doc["phone"];
            userOwner.email  = doc["email"];
            userOwner.city   = doc["city"];
            userOwner.state  = doc["state"];
            userOwner.photo  = doc["photo"];

            event.owner = userOwner;

            return userOwner;
          });

          events.add(event);
        });

        return events;
    });
  }

  Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
    List<Event> events = snapshot.data;

    return new ListView.builder(
      itemCount: events.length,
      itemBuilder: (BuildContext context, int index){
        return item(events[index]);
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Eventos'), 
      ),
      body: new FutureBuilder(
        future: getEvents(),
        builder: (BuildContext context, AsyncSnapshot snapshot){
          switch (snapshot.connectionState) {
            case ConnectionState.waiting: return new Text("Loading...");
            default: 
              if (snapshot.hasError)
                return new Text("Erro: ${snapshot.error}");
              else
                return createListView(context, snapshot);
          }
        },
      ),
      floatingActionButton: new FloatingActionButton(
        tooltip: 'Novo',
        child: new Icon(Icons.add),
        onPressed: () async {
          Navigation navigation = new Navigation();
          navigation.navigaTo(context, CadastroUsuario());
          },
      ),
    );
  }

  Widget item(Event event) {
    return new Card(
      elevation: 4.0,
      child: new Column(
        children: <Widget>[
          new Row(
            children: <Widget>[
              new Column(
                children: <Widget>[
                  new Text(event.owner.name.toString(),
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Column(
                children: <Widget>[
                ],
              )
            ],
          ),
          new Container(
            color: Colors.blue,
            height: 150.0,
          ),
          new Row(
            children: <Widget>[
              new Row(
                children: <Widget>[
                  new Text(event.description.toString(), 
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row(
                children: <Widget>[
                  new Text(event.location.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row(
                children: <Widget>[
                  new Text(event.city.toString() +' - '+ event.state.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              )
            ]
          )          
        ],
      )
    );
  }
}

Как я могу решить эту проблему? Есть ли другой способ сделать это?

PS: Я был бы признателен, если бы вы тоже привели мне пример

Можете ли вы проверить, действительно ли getEvents работает и возвращает непустой набор данных? Может быть, напишите тест, чтобы сначала проверить, если это возможно.

aubykhan 21.10.2018 20:33

Он работает нормально, проблема в том, что getevents завершает работу после завершения Listview.builder.

Matheus Miranda 21.10.2018 23:54
Интеграция Angular - Firebase Analytics
Интеграция Angular - Firebase Analytics
Узнайте, как настроить Firebase Analytics и отслеживать поведение пользователей в вашем приложении Angular.
0
2
452
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поскольку я не могу запустить ваш код, потому что он имеет другие зависимости, я постараюсь помочь вам как можно лучше, не тестируя его.

Одна вещь, которую следует помнить о флаттере (что значительно упростило мне понимание), заключается в том, что представление никогда не обновляется, пока вы не вызовете этот метод.

this.setState(() {});

Поэтому, когда вы на 100% уверены, что данные загружены, вызовите эту функцию. Это перестроит ваше представление и снова вызовет функцию сборки, которая должна обновить ваше представление. Я надеюсь, это поможет вам.

Зная это, вы могли бы значительно упростить свой код. Вы можете просто создать список с переменной как Children. Заполните эту переменную в своей асинхронной функции и снова вызовите setState. Это заполнит список.

Он использует FutureBuilder, который устраняет необходимость в setState. Это не связано

Rémi Rousselet 20.10.2018 23:31

Спасибо, но если я вызову setState после загрузки всех данных, мое приложение зайдет в бесконечный цикл.

Matheus Miranda 21.10.2018 03:34

Опять чувак ... Спасибо, ты заставил меня думать иначе, и я нашел способ решить свою проблему! Отмечу ваш ответ, потому что вы помогли мне увидеть другой путь!

Matheus Miranda 22.10.2018 01:56

Наконец-то я нашел способ ... Я инициализирую слушатель в initState, и когда в моем хранилище меняются изменения, я использую setState для восстановления обычного представления списка.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:project/Methods.dart';
import 'package:project/Views/CadastroUsuario.dart';
import 'package:project/classes/eventos.dart';

class ListagemEventos extends StatefulWidget {
  @override
  ListagemEventosState createState() => new ListagemEventosState();
}

class ListagemEventosState extends State<ListagemEventos> {
  List<Event> _events;

  @override
  void initState() {
    super.initState();
    _events = new List<Event>();
    Firestore.instance.collection("events").snapshots().listen((snapshot){
      getEvents(snapshot);
    });
  }

  void getEvents(QuerySnapshot eventsDoc) {
    List<Event> events = new List<Event>();

    eventsDoc.documents.forEach((doc) async {
      Event event = new Event();  
      String id;         

      event.description      = doc["description"];
      event.city             = doc["city"];
      event.state            = doc["state"];
      event.location         = doc["location"];
      event.date             = doc["date"];
      event.placesAvailable  = doc["placesAvailable"];
      event.totalPlaces      = doc["placesTotal"];

      id = doc["userId"];
      event.owner = new UserOwner();

      CollectionReference eventsDoc = Firestore.instance.collection("users");
      event.owner = await eventsDoc.document(id).get().then((doc) {
        UserOwner userOwner = new UserOwner();
        userOwner.userid = id;
        userOwner.name   = doc["name"];
        userOwner.phone  = doc["phone"];
        userOwner.email  = doc["email"];
        userOwner.city   = doc["city"];
        userOwner.state  = doc["state"];
        userOwner.photo  = doc["photo"];

        event.owner = userOwner;

        return userOwner;
      });

      events.add(event);
      setState(() {
        _events = events;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Eventos'), 
      ),
      body: 
      _events.length == 0
      ?
        new Center(child: new CircularProgressIndicator())
      :
        new ListView.builder(
          itemCount: _events.length,
          itemBuilder: (BuildContext context, int index){
            return item(_events[index]);
          }
        )
      ,floatingActionButton: new FloatingActionButton(
        tooltip: 'Novo',
        child: new Icon(Icons.add),
        onPressed: () async {
          Navigation navigation = new Navigation();
          navigation.navigaTo(context, CadastroUsuario());
          },
      ),
    );
  }

  Widget item(Event event) {
    return new Card(
      elevation: 4.0,
      child: new Column(
        children: <Widget>[
          new Row(
            children: <Widget>[
              new Column(
                children: <Widget>[
                  new Text(event.owner.name.toString(),
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Column(
                children: <Widget>[
                ],
              )
            ],
          ),
          new Container(
            color: Colors.blue,
            height: 150.0,
          ),
          new Row(
            children: <Widget>[
              new Row(
                children: <Widget>[
                  new Text(event.description.toString(), 
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row(
                children: <Widget>[
                  new Text(event.location.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row(
                children: <Widget>[
                  new Text(event.city.toString() +' - '+ event.state.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              )
            ]
          )          
        ],
      )
    );
  }
  }

Другие вопросы по теме