Как объединить несколько потоков данных в одном BLOC? - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть виджет для представления списка магазинов, отсортированных по ближайшим к пользователю текущим местоположениям, также должна применяться фильтрация.

Данные в:

  1. Хранит данные, поступающие из потокаКоллекция Firestore
  2. Текущее местоположение пользователя из geolacator.
  3. Параметры фильтрации из общих настроек (могут быть изменены в любое время)
  4. Режим сортировки списка, выбранный пользователем

Вывод данных: отфильтровано, отсортировано, список магазинов.

Какой шаблон является наилучшим в данном случае?

Ответы [ 4 ]

0 голосов
/ 15 февраля 2019

В этой ситуации я думаю, что есть несколько асинхронной обработки.Эта реализация может быть сложной.И есть возможность состязания.

Я буду реализовывать следующим образом.

  1. Отделяем потоки Model от Firestore и видимой пользователем ViewModel в Bloc.Виджеты слушают только ViewModel. (Например, с StreamBuilder)
  2. Ограничить обработку бизнес-логики только в блоке.Во-первых, переместите обработку с SharedPreferences в Bloc.
  3. Создайте класс UserControl только для пользовательского ввода.
  4. Обработка ветви зависит от типа пользовательского ввода расширенного UserControl

Надеюсьвам это вам поможет.

Например:

import 'dart:async';
import 'package:rxdart/rxdart.dart';

class ViewModel {}

class DataFromFirestoreModel {}

abstract class UserControl {}

class UserRequest extends UserControl {}

class UserFilter extends UserControl {
  final String keyWord;

  UserFilter(this.keyWord);
}

enum SortType { ascending, descending }

class UserSort extends UserControl {
  final SortType sortType;

  UserSort(this.sortType);
}

class Bloc {
  final controller = StreamController<UserControl>();
  final viewModel = BehaviorSubject<ViewModel>();

  final collection = StreamController<DataFromFirestoreModel>();

  Bloc() {
    controller.stream.listen(_handleControl);
  }

  _handleControl(UserControl control) {
    if (control is UserRequest) {
      _handleRequest();
    } else if (control is UserFilter) {
      handleFilter(control.keyWord);
    } else if (control is UserSort) {
      handleSort(control.sortType);
    }
  }

  _handleRequest() {
    //get location
    //get data from sharedPreferences
    //get data from firestore

    ViewModel modifiedViewModel; // input modifiedViewModel
    viewModel.add(modifiedViewModel);
  }

  handleSort(SortType sortType) {
    final oldViewModel = viewModel.value;
    //sorting oldViewModel

    ViewModel newViewModel; // input sorted oldViewModel
    viewModel.add(newViewModel);
  }

  handleFilter(String keyWord) {
    //store data to sharedPreferences
    //get data from Firestore

    ViewModel modifiedViewModel; // input modifiedViewModel
    viewModel.add(modifiedViewModel);
  }
}
0 голосов
/ 15 февраля 2019

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

Способ, которым я построил это в своем Добавление тестирования в приложение Flutter * Пост 1004 * состоял в том, чтобы создать один входной поток, но добавить к сообщениям маркеры, указывающие, к какому потоку данных относится сообщение.из.Это сделало тестирование вменяемым.

0 голосов
/ 15 февраля 2019

rxdart: https://pub.dartlang.org/packages/rxdart если вы хотите объединить данные вместе, вы можете использовать

var myObservable = Observable.combineLatest3(
myFirstStream, 
mySecondStream, 
myThirdStream, 
(firstData, secondData, thirdData) => print("$firstData $secondData $thirdData"));    


you can combine from ( combineLatest2, combineLatest... combineLatest9 )

или CombineLatestStream, как в этом примере

     CombineLatestStream.list<String>([
        Stream.fromIterable(["a"]),
        Stream.fromIterable(["b"]),
        Stream.fromIterable(["C", "D"])])
        .listen(print);
0 голосов
/ 14 февраля 2019

Числа 2, 3 и 4 - это входные данные для блока, которые вы отправляете через приемники.Блок прослушивает эти приемники и соответствующим образом обновляет запрос Firestore.Одного этого может быть достаточно для того, чтобы Firestore отправлял соответствующие снимки в выходной поток, который прослушивает виджет.

Если вы не можете сортировать или фильтровать то, что вы хотите напрямую, с помощью API Firestore, вы можете использовать stream.map или нанесите StreamTransformer на него.Преобразователь дает вам большую гибкость для прослушивания потока и изменения или игнорирования событий на лету, реализуя его метод bind.

Таким образом, вы можете сделать что-то вроде:

Stream<Store> get stores => _firestoreStream
  .transform(filter)
  .transform(sort);

Посмотрите на эту страницу для потоков в дротике в целом и посмотрите на rxdart для более сложных манипуляций с потоками.

...