如何在一个BLOC中合并多个数据流?

时间:2019-02-14 19:32:33

标签: dart stream flutter

我有一个小部件来表示按与用户当前位置最近的位置排序的商店列表,还应该应用过滤。

数据输入:

  1. 存储来自Firestore集合流的数据
  2. 地理定位器的当前用户位置。
  3. 从共享首选项中过滤选项 (可以随时更改)
  4. 用户选择的列表排序方式

数据输出:经过过滤,排序的商店列表。

在这种情况下最佳做法是什么?

4 个答案:

答案 0 :(得分:1)

rxdart:https://pub.dartlang.org/packages/rxdart 如果您想将数据合并在一起,可以使用

read

或 CombineLatestStream    像这个例子

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


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

答案 1 :(得分:0)

数字2、3和4是要通过接收器发送的集团的输入。群组监听这些接收器,并相应地更新Firestore查询。仅此一项就足以使Firestore将适当的快照发送到小部件正在侦听的输出流。

如果您无法直接使用Firestore的API进行排序或过滤,可以使用stream.map或对其应用StreamTransformer。转换器通过实现其bind方法,为您提供了很大的灵活性来侦听流并即时更改或忽略事件。

因此您可以执行以下操作:

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

总体上看一下this page中的dart流,并查看rxdart中更复杂的流操作。

答案 2 :(得分:0)

根据个人经验,我发现对一个块有多个输入会导致难以测试代码。块内隐式的并发问题导致混乱的场景。

我在Adding testing to a Flutter app帖子中构建它的方式是创建单个输入流,但在消息中添加标记以指示消息属于哪个数据流。它使测试变得理智。

答案 3 :(得分:0)

在这种情况下,我认为存在多个异步处理。该实现可能很复杂。并且有可能出现比赛状态。

我将实现如下。

  1. 将Firestore中的Model流与Bloc中用户可见的ViewModel分开。窗口小部件仅侦听ViewModel。(例如,使用StreamBuilder)
  2. 仅在Bloc中限制业务逻辑处理。首先,将具有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);
  }
}