Загрузить список базы данных firebase с асинхронным прослушиванием в будущее

#firebase-realtime-database #dart #flutter

#firebase-база данных в реальном времени #dart #флаттер

Вопрос:

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

 FirebaseDatabase database = new FirebaseDatabase();

Query _newsQuery = database
    .reference()
    .child('news')
    .orderByChild('published')
    .limitToFirst(10);

Future<List<News>> loadNews() async {
  List<News> list = new List<News>();
   _newsQuery.onChildAdded.listen(onNewsAdded);
  return list;
}

Future<News> onNewsAdded(Event event) async {
  News n = News.fromSnapshot(event.snapshot);
  print(n.title);
  return n;
}
  

выдает результат 2 с двумя записями в базе данных, когда я выполняю его с помощью

 loadNews().then((List<News> newsList) {
  print(newsList.length);
});
  

Но я получаю

 I/flutter (19206): 0
I/flutter (19206): Title 1
I/flutter (19206): Title 2
  

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

Я не хочу использовать setState() ни в одном виджете, потому что я хочу использовать собственный одноэлементный обработчик базы данных для всех виджетов. По этой причине я хочу загрузить данные асинхронно и дождаться их в виджете.

Комментарии:

1. Что такое _newsQuery? Что вы ожидаете увидеть? Вроде как неясно, как работает ваш код.

2. Вы правы. Я пропустил добавление запроса, но это не имеет никакого отношения к асинхронной проблеме. Но я добавил недостающий код. Также вы можете увидеть на github.com/matthiaw/gbh_app/blob/master/lib/models/news.dart модель данных новостей.

Ответ №1:

Хорошо, я думаю, что нашел решение. После множества проб и ошибок у меня появляется идея с https://webdev.dartlang.org/articles/performance/event-loop . Используется и принудительно использует вложенное future для заполнения списка. Используется затем Completer для закрытия списка.

 Future<List<News>> loadNews() async {
  Completer c = new Completer<List<News>>();
  List<News> list = new List<News>();
  Stream<Event> sse = _newsQuery.onChildAdded;

  sse.listen((Event event) {
    onNewsAdded(event, list).then((List<News> newsList) {
      return new Future.delayed(new Duration(seconds: 0), ()=> newsList);
    }).then((_) {
       if (!c.isCompleted) {
         c.complete(list);
       }
      });
    });
    return c.future;
  }

Future<List<News>> onNewsAdded(Event event, List<News> newsList) async {
  News n = News.fromSnapshot(event.snapshot);
  print("ADD: " n.title);
  newsList.add(n);
  return newsList;
}
  

При этом я получаю результат

 I/flutter ( 5419): ADD: Title 1
I/flutter ( 5419): ADD: Title 2
I/flutter ( 5419): ADD: Title 3
I/flutter ( 5419): Size: 3
  

Комментарии:

1. Как я могу изменить это, если в onNewsAdded мне нужно выполнить пошаговое выполнение <dynamic> из firebase? Мне нужно выполнить несколько проверок и противовесов, чтобы убедиться, что я могу добавить элемент в свой список, поэтому я застрял на том, как дождаться завершения цикла for, чтобы получить все необходимые данные и вернуть их.