Dart语言正确使用stream

移动端开发
Dart处理异步的API:
 1、Stream返回多个结果
 2、Future返回一个结果
 创建Stream的方式:
 1、Stream的构造方法
 Stream.periodic(
     Duration period,
     [T computation(
         int computationCount
     )?]
 ) 
 Stream periodicStream = Stream.periodic(Duration(seconds: 2), (num) {
   return num;
 });
 periodic构造方法主要有两个参数,第一个参数类型为Duration(时间间隔),第二个参数类型为Function,Function每隔一个Duration(时间间隔)会被调用一次,参数num为事件调用的次数,从0开始依次递增。
 2、将函数的返回值 声明为Stream
 Stream timedCounter(Duration interval, [int maxCount]) async* {
   int i = 0;
   while (true) {
    //延迟interval(时间间隔)执行一次
     await Future.delayed(interval);
     //返回i  i++
     yield "stream返回${i++}";
     if (i == maxCount) break;
   }
 }
 yield为一个用async *修饰返回值为Stream的函数返回一个值,它就像return,不过他不会结束函数。
 3、使用StreamController
   var _controller = StreamController();
 var _count = 1;
 createStream() {
   //函数每隔一秒调用一次
     Timer.periodic(Duration(seconds: 1), (t) {
       _controller.sink.add(_count);
       _count++;
     });
   }
 使用_controller的两个属性,使用_controller.Stream获取流,使用_controller.sink.add向流中添加数据,上面的例子使用定时器,每隔一秒向流中添加数据_count。
 Stream的常用方法
 listen作为使用Stream最重要的方法,主要用于监听流的数据变化,每当流的数据变化时,listen中的方法都会被调用。
 periodicStream.listen((event) {   print(event); });
 listen方法默认参数为Function,参数中的event为上面示例中返回的num,每当流返回新的数据时,listen方法都会被调用。
 listen的onError参数当流出现错误时调用。
 listen的onDone参数当流关闭时调用。
 还有一个cancelOnError属性,默认情况下为true,可以将其设置为false以使订阅在发生错误后也能继续进行。
 map
 Stream.periodic(Duration(seconds: 1), (num) {
     return num;
   }).map((num) => num * 2)
 使用map将流返回的数据进行转换
 asBroadcastStream()&broadcast
 通过Stream的asBroadcastStream()或StreamController的broadcast将单订阅的流转换为多订阅流
 什么是单订阅流和多订阅流?
 3.3.1 单订阅流
 单订阅流顾名思义,此流只能有一个订阅者,也就是单订阅流的listen方法只能被调用一次,当第二次调用单订阅流的listen时会报错,值得一提的是,当我们创建流时,默认创建的就是单订阅流。
 3.3.2 多订阅流
 顾名思义,此流可以有多个订阅者,也就是多订阅流的listen方法可以被多次调用,通过Stream的asBroadcastStream()或StreamController的broadcast将单订阅流转换为多订阅流。
 创建多订阅流
 Stream broadcastStream = Stream.periodic(Duration(seconds: 5), (num) {
   return num;
 }).asBroadcastStream();
 var _controller = StreamController.broadcast()
 单订阅流与多订阅流的区别
 第一个区别就是上面提到的订阅者数量的区别
 第二个区别就是单订阅流会持有自己的数据,当订阅者出现时将自身持有的数据全部返回给订阅者,而多订阅流不会持有任何数据,如果多订阅流没有订阅者,多订阅流会把数据丢弃。
 单订阅流与多订阅流的第二种区别的两种流程图
 
 处理 Stream 的方法
 下面这些 Stream 类中的方法可以对 Stream 进行处理并返回结果:
 Future get first;
 Future get isEmpty;
 Future get last;
 Future get length;
 Future get single;
 Future any(bool Function(T element) test);
 Future contains(Object needle);
 Future drain([E futureValue]);
 Future elementAt(int index);
 Future every(bool Function(T element) test);
 Future firstWhere(bool Function(T element) test, {T Function() orElse});
 Future fold(S initialValue, S Function(S previous, T element) combine);
 Future forEach(void Function(T element) action);
 Future join([String separator = ""]);
 Future lastWhere(bool Function(T element) test, {T Function() orElse});
 Future pipe(StreamConsumer streamConsumer);
 Future reduce(T Function(T previous, T element) combine);
 Future singleWhere(bool Function(T element) test, {T Function() orElse});
 Future> toList();
 Future> toSet();
 管理流订阅
 可以使用StreamSubscription对象来对流的订阅进行管理,listen方法的返回值就是StreamSubscription对象
 StreamSubscription subscription =
     Stream.periodic(Duration(seconds: 1), (num) {
     return num;
   }).listen((num) {
     print(num);
   });
 暂停订阅 subscription.pause();
 恢复订阅 subscription.resume();
 取消订阅 subscription2.cancel();
 当不需要监听流时记得调用这个方法,否则会造成内存泄漏
 操作流订阅的例子
 创建流
   static var _controller = StreamController();
   var _count = 1;
   createStream() {
     Timer.periodic(Duration(seconds: 1), (t) {
       _controller.sink.add(_count);
       _count++;
     });
   }
 创建监听及监听管理对象
   StreamSubscription subscription2 = _controller.stream.listen((event) {
     print("单订阅流$event");
   });
 操作流订阅的方法
 createStream();
 Future.delayed(Duration(seconds: 3), () {
   print("暂停");
   subscription2.pause();
 });
 Future.delayed(Duration(seconds: 5), () {
   print("继续");
   subscription2.resume();
 });
 Future.delayed(Duration(seconds: 7), () {
   print("取消");
   subscription2.cancel();
 });
 在Flutter中使用StreamBuilder组件
 5.1 StreamBuilder组件介绍
 StreamBuilder组件主要有两个参数
 第一个参数stream,要订阅的流
 第二个参数builder,widget构建函数
 可以使用builder函数的snapshot.connectionState属性根据流的不同状态返回不同的组件
 每当StreamBuilder监听的stream有数据变化时,builder函数就会被调用,组件重新构建。
 5.2示例代码
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_demo/util/util.dart';
 /// Copyright (C), 2020-2020, flutter_demo
 /// FileName: streamBuilder_demo
 /// Author: Jack
 /// Date: 2020/12/27
 /// Description:
 class StreamBuilderDemo extends StatelessWidget {
   //创建流
   Stream _stream() {
     Duration interval = Duration(seconds: 1);
     Stream stream = Stream.periodic(interval, (num) {
       return num;
     });
     stream = stream.take(59);
     return stream;
   }
 @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: AppBar(
         title: Text('Stream Demo'),
       ),
       body: Center(
         child: StreamBuilder(
           stream: _stream(),
           builder: (BuildContext context, AsyncSnapshot snapshot) {
             if (snapshot.connectionState == ConnectionState.done) {
               return Text(
                 '1 Minute Completed',
                 style: TextStyle(
                   fontSize: 30.0,
                 ),
               );
             } else if (snapshot.connectionState == ConnectionState.waiting) {
               return Text(
                 'Waiting For Stream',
                 style: TextStyle(
                   fontSize: 30.0,
                 ),
               );
             }
             return Text(
               '00:${snapshot.data.toString().padLeft(2, '0')}',
               style: TextStyle(
                 fontSize: 30.0,
               ),
             );
           },
         ),
       ),
     );
   }
 }

我的博客,记录,笔记