【问题标题】:Dart - Get the last or the first value of a streamDart - 获取流的最后一个或第一个值
【发布时间】:2021-10-05 22:53:38
【问题描述】:

我有一个流,我需要使用这个流的最后一个值,如果这个流没有发出任何值,我需要等待第一个值。我只想使用这个值一次。正确的做法是什么?

【问题讨论】:

    标签: dart rxdart


    【解决方案1】:

    听起来您想要由流发出的最近事件(可能是广播流,否则在您收听之前没有事件),或者,如果之前没有事件,您需要 next 事件。

    对于普通的 Dart Stream,这是不可能的。它不记得以前的事件。您需要之前收听过该流,才能知道最近的事件是什么(但如果您这样做,它不一定是广播流)。

    您可以相当轻松地构建自己的记忆流包装器(但与异步编程一样,您需要注意竞争条件)

    // Copyright 2021 Google LLC.
    // SPDX-License-Identifier: Apache-2.0
    import "dart:async";
    
    /// Listens to [source] to returned stream.
    ///
    /// Each listener on the returned stream receives the most recent
    /// event sent on [source] followed by all further events of [source]
    /// until they stop listening.
    /// If there has been no events on [source] yet, only the further events
    /// are forwarded.
    Stream<T> mostRecentStream<T>(Stream<T> source) {
      var isDone = false;
      var hasEvent = false;
      T? mostRecentEvent;
      List<MultiStreamController>? pendingListeners;
      var listeners = <MultiStreamController>[];
    
      void forEachListener(void Function(MultiStreamController) action) {
        var active = 0;
        var originalLength = listeners.length;
        for (var i = 0; i < listeners.length; i++) {
          var controller = listeners[i];
          if (controller.hasListener) {
            listeners[active++] = controller;
            if (i < originalLength) action(controller);
          }   
        }
        listeners.length = active;
      }
    
      source.listen((event) {
        mostRecentEvent = event;
        hasEvent = true;
        forEachListener((controller) {
          controller.addSync(event);
        });
      }, onError: (e, s) {
        forEachListener((controller) { 
          controller.addErrorSync(e, s);
        });
      }, onDone: () {
        isDone = true;
        for (var controller in listeners) {
          controller.close();
        }
        listeners.clear();
      });
    
      return Stream<T>.multi((controller) {
        if (hasEvent) controller.add(mostRecentEvent as T);
        if (isDone) {
          controller.close();
        } else {
          listeners.add(controller);
        }  
      });
    }
    

    这样,您可以简单地执行var recentStream = mostRecentStream(yourStream),然后再执行recentStream.first 来获取最新事件,或者,如果没有,则获取下一个事件(如果有,如果流发生错误,您会收到错误消息)完全是空的)。

    【讨论】:

      猜你喜欢
      • 2019-03-09
      • 2016-12-12
      • 1970-01-01
      • 2010-12-28
      • 1970-01-01
      • 2012-01-22
      • 2018-10-20
      • 1970-01-01
      • 2021-11-19
      相关资源
      最近更新 更多