我们当前有一个返回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;
}
所以这里发生的是:
_getLocationPermission()
方法,以便我们可以测试用户是否授予我们访问其设备(Android或iOS)上的位置服务的权限; Stream<Position>
,该值将在设备每次注册位置更改时更新。我觉得我们也可以不用等待就返回Future
来处理这个问题。类似于:
Stream<Position>
类的实例; _eventChannel.receiveBroadcastStream
方法返回的then()
的{{1}}方法中检查权限并调用Future<PermissionStatus>
的逻辑(因此我们不必等待); _getLocationPermission()
复制到先前创建(并返回)的流中。这似乎是可行的,但还包括管理流的一些开销,并确保在插件的实时周期中或当用户取消订阅将事件传递到{{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
,原始流的行为就好像是真实流一样。