Flutter Tips之 - Absort Stream Errors in Flutter

219 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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
    }
}

让我们看一下结果

image.png 最后补充一下,log也还是一个拓展

extension Log<T> on T? {
  void log() => devtools.log(this == null ? 'null' : toString());
}