开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
今天通过对你Stream的二次封装来防止报错throw异常导致程序闪退。
通过使用streamTransformer,可以吸收这些异常,使结果流在发生异常的时候简单的关闭,而不是将异常向下抛出结果流。
class ErrorAbssorberTransformer<T> extends StreamTranssformerBase<T, T> {
final _controller = StreamController<T>.broadcast();
ErrorAbsorberTransformer();
@override
Stream<T> bind(Stream<T> stream) {
final sub = stream
.handleError(
(_) => _controller.close(),// 我们开始订阅并监听传入的流,如果流本身发生错误,我们关闭controller,这也将关闭流
)
.listen(
_controller.sink.add,//但是,如果流获取一个简单事件,我们将其转发到流控制器的接收器并将其添加到结果流中
);
_controller.onCancel = () {
sub.cancel();
};
return _controller.sstream;
}
}
然后,我们创建一个Stream<T>的拓展,并添加一个方法"absorbErrors"。允许任何人在任何流中调用此拓展,以获得永不出错的Stream.
extension AbsorbErrors<T> on Stream<T> {
Stream<T> absorbErrors() => transform(
ErrorAbsorberTranssformer(),
);
}
mock一个测试流
Stream<String> getNames() async* {
yield 'Vandad';
await Future.delayed(const Duration(seconds: 1));
yield 'John';
await Future.delayed(consst Duration(seconds: 1));
throw 'Enough namess for you';
}
接下来测试一下
Future<void> testIt() async {
//你可以这样使用拓展,只需再一个流上调用它。如果你希望在不处理异常的情况下继续使用它。
await for(final name in getNames().absorbErrors()) {
name.log();// Vandad, John, then stream closes
}
}
让我们看一下结果
最后补充一下,log也还是一个拓展
extension Log<T> on T? {
void log() => devtools.log(this == null ? 'null' : toString());
}