【问题标题】:How to return multiple data via StreamController?如何通过 StreamController 返回多个数据?
【发布时间】:2020-09-11 19:18:58
【问题描述】:

我正在尝试动态获取谷歌地图中的标记并在数据库更新时更改标记颜色。我成功地获取了谷歌地图上的标记,但我无法正确收听firestore 中的标记更新。

这是我的profiles 数据库结构。 profiles 集合包含配置文件基本详细信息列表。

每个profile(document) 都包含一个attendance 子集合,其中包含date 作为文档和出勤数据。

我通过循环遍历profiles 集合在谷歌地图中获取了标记。现在,我正在努力检查每个 profile(document) -> attendance -> date -> is_coming: true or false,如果是 false 我必须更新特定标记的颜色.

这就是我尝试收听每个出勤记录的方式。

  final StreamController<Attendance> _attendanceController =
      StreamController<Attendance>.broadcast();

  Stream checkAttendance({String member, String batch}) {
    _profileCollectionReference //profiles collection
        .document(member)
        .collection('attendance')
        .document(toDate) //date
        .snapshots()
        .forEach((snapshot) {
      var data = Attendance.fromData(
          data: snapshot.data, profileId: member, batchId: batch); //returns as Attendance type

      _attendanceController.add(data);
    });

    return _attendanceController.stream;
  }

问题是,它只返回最后一条记录或覆盖以前的记录。这个checkAttendance 流函数也在循环内部运行。

我必须不断收听每个attendance 子集合。我不能以future 的身份返回,因为我必须实时更新。

在这种情况下我不能使用 StreamBuilder,因为我使用的是 MVVM 架构 Stacked

我无法弄清楚。任何将不胜感激。

更新

这就是我返回标记的方式

  final FirestoreService _firestoreService = locator<FirestoreService>();

  Map<MarkerId, Marker> _markers = <MarkerId, Marker>{};
  Map<MarkerId, Marker> get markers => _markers;

  void getMembers(Batch batch) {
    setBusy(true);

    _firestoreService.getMembers(batch.id).listen((event) { //returns the list of members assigned to a batch
      List<Profile> members = event;

      if (members != null && members.length > 0) {
        members.forEach((member) { //loop through list of members
          if (member.attendingDays.contains(toDay) && !member.onVacation) { //validation
            createAttendance(member.id, batch.id);

         //this is code part where I'm checking attendance
            _firestoreService
                .checkAttendance(member: member.id, batch: batch.id)
                .listen((attendanceEvent) { //returns list of attendance records of members
              List<Attendance> attendances = attendanceEvent;

              if (attendances != null && attendances.length > 0) {
                attendances.forEach((attendance) {
                  final MarkerId markerId = MarkerId(member.id);
                  final Marker marker = Marker(
                    markerId: markerId,
                    position: LatLng(
                      member.pickupLatLng.latitude,
                      member.pickupLatLng.longitude,
                    ),
                    icon: (attendance.isComing)
                        ? BitmapDescriptor.defaultMarkerWithHue(
                            BitmapDescriptor.hueGreen)
                        : BitmapDescriptor.defaultMarker,
                    flat: true,
                    zIndex: 2,
                    anchor: Offset(0.5, 0.5),
                    onTap: () {},
                  );

                  _markers[markerId] = marker;
                  notifyListeners();
                });
              }
            });
          }
        });
      }

      setBusy(false);
    });
  }

【问题讨论】:

  • "如何通过 StreamController 返回多个数据流?" - 所以你想要StreamController&lt;List&lt;Attendance&gt;&gt;,而不是StreamController&lt;Attendance&gt;?我的意思是你的流中的每个元素都应该是 Attendance 对象的列表,而不是简单的 Attendance?
  • @pskink 即使我以List&lt;Attendance&gt; 的身份返回,它也只返回最后一个配置文件document 数据。
  • 所以将当前的data 附加到某个列表并使用该列表调用StreamController.add(),但实际上您可以使用简单的Stream.map 方法来做到这一点 - 没有Stream.forEach,没有StreamControllers等
  • @pskink 您的想法部分可行。如果我在终端中打印该值,它会正确打印。但如果我更新标记,所有其他标记的颜色也会发生变化。在终端中,该值会打印几次。你有什么想法吗?
  • 我在你的代码中没有看到任何标记,所以......基本上这个想法是:void main() { var list = []; Stream.periodic(Duration(seconds: 1), (i) =&gt; i) .take(10) .map((i) =&gt; list..add(i)) .listen(print); } - 这里你有一个在 1 秒延迟内生成数字 0..9 和 map() 的流方法附加该数字,因此输出流具有不断增长的数字列表

标签: android ios flutter dart mvvm


【解决方案1】:

实际上我找到了一种方法来改变我的情况下标记的颜色。

按照@pskink 的建议,我将出勤数据作为列表返回。

然后我创建了以下函数。

  void checkAttendance(String member, String batch) {
    _firestoreService
        .checkAttendance(member: member, batch: batch)
        .listen((attendanceEvent) {
      List<Attendance> attendances = attendanceEvent;

      if (attendances != null && attendances.length > 0) {
        attendances.forEach((attendance) {
          final MarkerId markerId = MarkerId(attendance.profileId);
          final Marker matchedMarker = _markers[markerId];

          if (!attendance.isComing) { //validation
            final Marker newMarker = matchedMarker.copyWith(
                iconParam: BitmapDescriptor.defaultMarker);
            _markers[markerId] = newMarker;
          } else {
            final Marker newMarker = matchedMarker.copyWith(
                iconParam: BitmapDescriptor.defaultMarkerWithHue(
                  BitmapDescriptor.hueGreen));
            _markers[markerId] = newMarker;            
          }
          notifyListeners();
        });
      }
    });
  }

我已经将标记提取到谷歌地图。因此,使用出勤数据我也将返回profile id。每个marker_id 等于profile id

因此,我所做的是返回匹配的marker_idprofile id,然后使用.copyWith() 函数制作匹配的标记,并根据验证更改图标颜色。

最后我自己找到了解决方案。我希望这个解决方案可能对某人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 2018-10-30
    • 1970-01-01
    • 2011-03-14
    • 2022-01-12
    • 2021-12-13
    相关资源
    最近更新 更多