Получение текущего значения из Stream

Существует StreamBuilder (использующий RxDart), который отображает некоторую дату. После нажатия на виджет InkWell мне нужно рассчитать новую дату на основе старой. Приведенный ниже код просто объясняет алгоритм, но когда я его запускаю, ничего не происходит и выполнение останавливается после подчеркнутой строки, т.е. я никогда не вижу значение lastCalcDate.

Графический интерфейс:

child: StreamBuilder(
  stream: bloc.getDate,
  builder: (context,snapshot) {
    return InkWell(
      onTap: () => tapHandler
    );
}),

void tapHandler() async {
  var lastCalcDate = await bloc.getDate.single;
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  print(lastCalcDate);
  var newCalcDate = lastCalcDate.add(Duration(days:1));
  bloc.setDate(newCalcDate)
}

BLoC:

class Bloc {
  // BehaviourSubject is usedto be sure that last sent date will be accessible in `tapHandler`.
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  Function(DateTime) get setDate => _dateSubject.add;
}

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

BLoC (обходной путь):

class Bloc {
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  DateTime _date;
  void setDateWorkaround(DateTime date) {
    _date = date;
    _dateSubject.add(date);
  }
}

Не могли бы вы дать мне совет. Что я сделал не так?


person BambinoUA    schedule 18.04.2019    source источник


Ответы (1)


single не будет работать, потому что он вернет следующий элемент в потоке, однако он должен быть добавлен первым. Это означает, что single будет просто ждать следующего элемента, а в вашем случае этого не произойдет.

Поскольку вы уже используете rxdart и BehaviorSubject, вы можете легко получить доступ к текущему элементу следующим образом:

class Bloc {
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  Function(DateTime) get setDate => _dateSubject.add;

  DateTime get currentDate => _dateSubject.value;
}

В этом случае я использую BehaviorSubject.value, в чем собственно весь смысл этого класса.

Теперь вы можете просто использовать currentDate в своем обработчике касаний:

void tapHandler() async {
  var lastCalcDate = bloc.currentDate;
  print(lastCalcDate);
  var newCalcDate = lastCalcDate.add(Duration(days:1));
  bloc.setDate(newCalcDate)
}
person creativecreatorormaybenot    schedule 18.04.2019
comment
привет, как я могу его получить без использования rx? - person ch271828n; 24.01.2021
comment
Если кто-то столкнется с той же проблемой: похоже, что в пакете rxdart произошло критическое изменение, из-за которого вы больше не можете использовать .value непосредственно в BehaviorSubject. Вам нужно будет использовать _dateSubject.valueWrapper.value. Ссылка в этом ответе на документацию BeahviorSubject.value теперь недействительна. - person kk_; 03.04.2021