Как вернуть метод List из Stream <List>? флаттер - PullRequest
0 голосов
/ 09 марта 2020

Я все еще новичок во Flutter и использую flutter_bloc для управления состоянием. В блоке c я слушаю метод репозитория Stream<List<UserAlert>> alerts(). В этом методе я слушаю события .onChildAdded и .onChildRemoved на узле базы данных Firebase в реальном времени и обновляю локальный List<UserAlert> alerts, но мне не удается вернуть его после обновления, поэтому я получаю нулевое значение для blo c слушатель. NoSuchMethodError: The method 'listen' was called on null. Я решил управлять им вручную, поскольку не хочу загружать весь узел при каждом изменении, как это происходит при прослушивании .onValue. Я пробовал return alerts as Stream<List<UserAlert>> внутри обеих областей моментальных снимков Firebase, но получаю ошибку приведения типа Я пробовал Stream.value(alerts) как внутри каждой области видимости, так и в качестве самой последней вещи в методе, но все равно возвращает ноль. Как я могу получить alerts для возврата в виде потока? Большое спасибо за вашу помощь.

Метод репозитория:

Stream<List<UserAlert>> alerts() {
    print('alerts() called');
    Stream<List<UserAlert>> alertStream;

    List<UserAlert> alerts = [];
    // Option 2  return a list manually updated by two different events: More complicated but very efficient(bandwidth), lowest data consuming = Lowest Firebase bill.
    // returns one event per node record at app start and only new afterwards

    _alertSubscription = _databaseReference.onChildAdded.listen((Event event) {
      print(' observer .childAdded: added alert is : ${event.snapshot.value}');
      UserAlert userAlert = UserAlert.fromSnapshot(event.snapshot);
      alerts.add(userAlert);
//      alertStream = Stream.value(alerts); // alerts as Stream<List<UserAlert>>;
//      return alerts;

      print(
          'observer .childAdded: alerts are: $alerts and total alerts are ${alerts.length}');
    });

    // returns one event per node removed record
    _alertSubscription =
        _databaseReference.onChildRemoved.listen((Event event) {
      print(
          'observer .childRemoved: removed alert is : ${event.snapshot.value}');
      int index = alerts.indexWhere(
          (userAlert) => userAlert.id.startsWith(event.snapshot.value['Id']));

      print('index to remove is: $index');
      alerts.removeAt(index);

//      return alerts;
      print(
          'observer .childRemoved: alerts after removing are: $alerts and total alerts are ${alerts.length}');
//      return alerts;
    });
//    yield* alertStream;
    Stream.value(alerts);
  }

Blo c Слушатель:

Stream<AlertState> _mapLoadAlertToState() async* {
    _alertSubscription?.cancel();
    _alertSubscription = _alertRepository
        .alerts()
        .listen((alerts) => add(AlertsUpdated(alerts)));
////        (List<UserAlert> alerts) {
////      print('_mapLoadAlertToState() userAlterts are: $alerts');
////      add(AlertsUpdated(alerts));
//    });
  }

Ответы [ 2 ]

0 голосов
/ 09 марта 2020

Я изменил подход, и теперь я получаю данные из базы данных, как я ожидал от предыдущего подхода. Я решил разделить метод Repository на два разных метода, которые преобразуют потоки в Stream<UserAlert:

Stream<UserAlert> addedAlert() {
    print('addedAlert() called');
    handleData(Event event, EventSink<UserAlert> sink) =>
        sink.add(UserAlert.fromSnapshot(event.snapshot));

    final transformer = StreamTransformer<Event, UserAlert>.fromHandlers(
        handleData: handleData);

    return _databaseReference.onChildAdded.transform(transformer);
  }

  Stream<UserAlert> removedAlert() {
    print('removedAlert() called');
    handleData(Event event, EventSink<UserAlert> sink) =>
        sink.add(UserAlert.fromSnapshot(event.snapshot));

    final transformer = StreamTransformer<Event, UserAlert>.fromHandlers(
        handleData: handleData);

    return _databaseReference.onChildRemoved.transform(transformer);
  }

и обрабатывают добавление и удаление из List<UserAlert> внутри метода blo c:

Stream<AlertState> _mapLoadAlertToState() async* {

    _addedAlertStreamSubcription =
        _alertRepository.addedAlert().listen((UserAlert alert) {
      print('received snapshot is:$alert.'); // prints null
      alerts.add(alert);
      print(
          'observer .childAdded: added alert is :$alert, we have ${alerts.length} active alerts, active alerts are: $alerts');
      add(AlertsUpdated(alerts));
    });

    _removedAlertStreamSubscription =
        _alertRepository.removedAlert().listen((UserAlert alert) {
      int index =
          alerts.indexWhere((userAlert) => userAlert.id.startsWith(alert.id));

      print('index to remove is: $index');
      alerts.removeAt(index);
      print(
          'observer .childRemoved: removed alert is :$alert, we have ${alerts.length} active alerts, active alerts are: $alerts');
      add(AlertsUpdated(alerts));
    });
  }

AlertUpdated затем сработает:

Stream<AlertState> _mapAlertsUpdatedToState(AlertsUpdated alert) async* {
    print(
        '_mapAlertsUpdatedToState() called, alerts are: ${alert.alerts} ');
    yield AlertLoaded(alert.alerts);
  } 

_mapAlertsUpdatedToState отпечатки показывают правильный список, но отпечатки с BlocListener отображаются только один раз с одним значением в списке.

BlocListener<AlertBloc, AlertState>(
            listener: (BuildContext context, AlertState state) {
          if (state is AlertLoaded) {
            List<UserAlert> userAlerts = (state).alerts;
            print(
                'AlertListener userAlerts are: $userAlerts and total alerts are : ${userAlerts.length}');
          }
        }),

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

0 голосов
/ 09 марта 2020

Вы можете использовать оператор yield для возврата потока:

Stream<AlertState> _mapLoadAlertToState() async* {
    Stream<List<UserAlert>> _stream = _alertRepository.alerts();
    await for(List<UserAlert> alerts in _stream){
        yield AlertsUpdated(alerts);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...