Объединить несколько потоков BehaviorSubject в один? - PullRequest
1 голос
/ 16 апреля 2019

Цель состоит в том, чтобы я использовал несколько потоков без необходимости вкладывать 3+ StreamBuilders.

Я уже использую rxdart, и я изучал слияние, но я не совсем понимаю правильный синтаксис его использования?

В настоящее время у меня есть файл Bloc под названием InfoBloc. Это код внутри InfoBloc

  final _name = BehaviorSubject<String>();
  final _description = BehaviorSubject<String>();
  final _picture = BehaviorSubject<File>();

  Observable<String> get name => _name.stream.transform(_validateName);
  Observable<File> get picture => _picture.stream;
  Observable<String> get eventDescription =>
      _description.stream.transform(_validateMessage);

  final _validateMessage = StreamTransformer<String, String>.fromHandlers(
      handleData: (eventMessage, sink) {
    if (eventMessage.length > 0) {
      sink.add(eventMessage);
    } else {
      sink.addError(StringConstant.eventValidateMessage);
    }
  });

  var obs = Observable.merge([])
  final _validateName = StreamTransformer<String, String>.fromHandlers(
      handleData: (String name, sink) {
    if (RegExp(r'[!@#<>?":_`~;[\]\\|=+)(*&^%0-9-]').hasMatch(name)) {
      sink.addError(StringConstant.nameValidateMessage);
    } else {
      sink.add(name);
    }
  });

  void dispose() async {
    await _description.drain();
    _description.close();
    await _name.drain();
    _name.close();
    await _picture.drain();
    _picture.close();
  }

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

 StreamBuilder(
   stream: _bloc.name,
   builder: (BuildContext context, AsyncSnapshot<String> snapshotName) {
     return StreamBuilder(
       stream: _bloc.eventDescription,
       builder: (BuildContext context, AsyncSnapshot<String> snapshotDescription) {
         return StreamBuilder(
           stream: _bloc.picture,
           builder: (BuildContext context, AsyncSnapshot<File> snapshotName) {

Но должен быть лучший способ сделать это.

Мечта состоит в том, чтобы я мог создать внутри файла InfoBloc что-то, что могло бы объединить все эти потоки, и мне нужно всего лишь использовать StreamBuilder для потоковой передачи этого объединенного потока.

1 Ответ

1 голос
/ 16 апреля 2019

Вы можете проверить метод combineLatest() для класса Observable. Он объединяет данные потоки в одну наблюдаемую последовательность с помощью функции объединения, так что полученная наблюдаемая не будет излучать, если все потоки не выпустили хотя бы один элемент.

Существует множество combineLatest() методов. Но так как у вас есть 3 потока, вы можете использовать combineLatest3().

Пример -

Observable.combineLatest3(
  new Observable.just("a"),
  new Observable.just("b"),
  new Observable.fromIterable(["c", "c"]),
  (a, b, c) => a + b + c)
.listen(print); //prints "abc", "abc"

Вы можете проверить эту ссылку для получения дополнительной информации.

ОБНОВЛЕНИЕ -

Вы можете обратиться к приведенному ниже примеру использования функции в вашем коде.

Observable<String> get name => _name.stream.transform(_validateName);
Observable<File> get picture => _picture.stream;
Observable<String> get eventDescription => _description.stream.transform(_validateMessage);
//Add this line to combine your Streams
Observable<bool> readyToSubmit => Observable.combineLatest3(name, picture, eventdescription, (value1, value2, value3) => true);
//We simply return true from the combiner function since we don't want to perform any operation on the Streams when combining.

Я использовал bool тип Observable только для примера. Вы можете изменить тип на Map<String, dynamic>' and add the Stream values into the Карта if you want to access the data from all three streams. And in your StreamBuilder` виджет, который вы можете использовать -

StreamBuilder(
   stream: _bloc.readyToSubmit,
   builder: //Your builder function here
)

Надеюсь, это поможет!

...