#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, чтобы получить все необходимые данные и вернуть их.