有没有一种方法可以避免必须等待异步方法返回流?

时间:2018-08-17 09:03:48

标签: asynchronous stream async-await dart

我们当前有一个返回Future<Stream<Position>>的方法,只是因为在内部,我们必须等待返回Future的方法的结果,然后才能调用另一个返回Stream<Position>的方法,我们实际上感兴趣。这是代码:

Future<Stream<Position>> getPositionStream(
    [LocationOptions locationOptions = const LocationOptions()]) async {
  PermissionStatus permission = await _getLocationPermission();

  if (permission == PermissionStatus.granted) {
    if (_onPositionChanged == null) {
      _onPositionChanged = _eventChannel
          .receiveBroadcastStream(
              Codec.encodeLocationOptions(locationOptions))
          .map<Position>(
              (element) => Position._fromMap(element.cast<String, double>()));
    }

    return _onPositionChanged;
  } else {
    _handleInvalidPermissions(permission);
  }

  return null;
}

所以这里发生的是:

  1. 我们等待_getLocationPermission()方法,以便我们可以测试用户是否授予我们访问其设备(Android或iOS)上的位置服务的权限;
  2. 如果用户授予我们许可,我们将返回Stream<Position>,该值将在设备每次注册位置更改时更新。

我觉得我们也可以不用等待就返回Future来处理这个问题。类似于:

  1. 手动创建并返回Stream<Position>类的实例;
  2. 处理从_eventChannel.receiveBroadcastStream方法返回的then()的{​​{1}}方法中检查权限并调用Future<PermissionStatus>的逻辑(因此我们不必等待);
  3. 将流中发送的事件从_getLocationPermission()复制到先前创建(并返回)的流中。

这似乎是可行的,但还包括管理流的一些开销,并确保在插件的实时周期中或当用户取消订阅将事件传递到{{1时,将其关闭并正确清理。 }}等

所以我想问题是,解决这种情况的最佳方法是什么?

1 个答案:

答案 0 :(得分:5)

您可以将代码编写为async*函数,该函数将返回Stream并且仍然允许正文中的await

Stream<Position> getPositionStream(
    [LocationOptions locationOptions = const LocationOptions()]) async* {
  PermissionStatus permission = await _getLocationPermission();

  if (permission == PermissionStatus.granted) {
    if (_onPositionChanged == null) {
      _onPositionChanged = _eventChannel
          .receiveBroadcastStream(
              Codec.encodeLocationOptions(locationOptions))
          .map<Position>(
              (element) => Position._fromMap(element.cast<String, double>()));
    }

    yield* _onPositionChanged;
  } else {
    _handleInvalidPermissions(permission);
  }
}

或者,如果您使用的是非async功能,则也可以使用package:async中的StreamCompleter。 即使您稍后仅获得真实流,它也允许您立即返回Stream。发生这种情况时,您可以用真实流“完成” StreamCompleter,原始流的行为就好像是真实流一样。