Flutter之异步编程(下)
Stream
Stream是Dart语言中所谓异步数列的东西,直白点就是一个异步数据队列。为了控制Stream我们通常采用StreamController来进行管理,sink作为入口函数,StreamController提供stream属性作为数据的出口,StreamController.stream.listen用来监听Stream是否有数据
一、Stream分类
- 单订阅流
- 多订阅流
二、Stream 创建
Flutter 提供了多种创建 Stream 的方式;
1.Stream.periodic
//stream_create_periodic.dart文件
import 'dart:async';
void main(){
//创建Stream
createStream();
}
createStream() async{
//使用periodic创建流,第一个参数为间隔时间,第二个参数为回调函数
Stream<int> stream = Stream<int>.periodic(Duration(seconds: 1), callBack);
//await for循环从流中读取
await for(var i in stream){
print(i);
}
}
//可以在回调函数中对值进行处理,这里直接返回了
int callBack(int value){
return value;
}
2.Stream.fromFutrue
//stream_create_from_future.dart文件
import 'dart:async';
void main(){
//创建一个Stream
createStream();
}
createStream() async{
print("开始测试");
//创建一个Future对象
Future<String> future = Future((){
return "异步任务";
});
//从Future创建Stream
Stream<String> stream = Stream<String>.fromFuture(future);
//await for循环从流中读取
await for(var s in stream){
print(s);
}
print("结束测试");
}
3.Stream.fromFutrues
//stream_create_from_futures.dart文件
import 'dart:io';
void main(){
//从多个Future创建Stream
createStreamFromFutures();
}
createStreamFromFutures() async{
print("开始测试");
Future<String> future1 = Future((){
//模拟耗时5秒
sleep(Duration(seconds:5));
return "异步任务1";
});
Future<String> future2 = Future((){
return "异步任务2";
});
Future<String> future3 = Future((){
return "异步任务3";
});
//将多个Future放入一个列表中,将该列表传入
Stream<String> stream = Stream<String>.fromFutures([future1,future2,future3]);
//读取Stream
await for(var s in stream){
print(s);
}
print("结束测试");
}
4.Stream.fromIterable
//stream_create_from_iterable.dart文件
import 'dart:async';
void main(){
//从一个集合创建Stream
createStream();
}
createStream() async{
print("开始测试");
//从集合创建Stream
Stream<int> stream = Stream<int>.fromIterable([1,2,3,4,5,6]);
//读取Stream
await for(var s in stream){
print(s);
}
print("结束测试");
}
- Stream 操作方法
1.stream.take
//stream_take.dart文件
import 'dart:async';
void main(){
//创建Stream
createStream();
}
void createStream() async{
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//指定发送事件个数
stream = stream.take(10);
//输出Stream
await for(int i in stream ){
print(i);
}
}
2.stream.takeWhile
//stream_take_while.dart文件
import 'dart:async';
void main(){
//创建Stream
createStream();
}
void createStream() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//根据返回结果做返回值的限制
stream = stream.takeWhile((data) {
//返回值的限制条件
return data < 8;
});
//输出Stream
await for (int i in stream) {
print(i);
}
}
3.stream.skio(int count)
//stream_skip.dart文件
import 'dart:async';
void main(){
//创建Stream,跳过指定个数元素
testSkip();
}
void testSkip() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//指定发送事件次数
stream = stream.take(10);
//跳过前两个元素
stream = stream.skip(2);
//输出Stream
await for (int i in stream) {
print(i);
}
}
4.stream.skioWhile
//stream_skip_while.dart文件
import 'dart:async';
void main(){
//创建Stream,按条件跳过元素
testSkipWhile();
}
void testSkipWhile() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//指定发送事件个数
stream = stream.take(10);
//根据条件跳过元素,条件为返回值小于5
stream = stream.skipWhile((data) => data<5);
//输出Stream
await for (int i in stream) {
print(i);
}
}
5.stream.toList()
//stream_to_list.dart文件
import 'dart:async';
void main(){
//创建Stream,将流中的数据放在List里
testToList();
}
void testToList() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//指定发送事件个数
stream = stream.take(10);
//将流中所有的数据收集存放在List中
List<int> listData = await stream.toList();
//输出List数据
for(int i in listData){
print(i);
}
}
5.stream.listen()
//stream_listen.dart文件
import 'dart:async';
void main(){
//创建Stream,使用list方法监听流
testListen();
}
void testListen() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
stream = stream.take(10);
//监听流
stream.listen((data){
print(data);
},onError:(error){
print("流发生错误");
},onDone:(){
print("流已完成");
}, cancelOnError: false);
}
6.stream.forEach()
//stream_for_each.dart文件
import 'dart:async';
void main(){
//创建Stream,使用Stream的forEach迭代输出数据
testForEach();
}
void testForEach() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
stream = stream.take(5);
//Stream迭代输出数据
stream.forEach((data) {
print(data);
});
}
7.stream.length
//stream_length.dart文件
import 'dart:async';
void main(){
//创建Stream,并统计事件的总数量
testStreamLength();
}
void testStreamLength() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
stream = stream.take(5);
//统计事件的总数量
var allEvents = await stream.length;
print(allEvents);
}
8.stream.length
//stream_length.dart文件
import 'dart:async';
void main(){
//创建Stream,并统计事件的总数量
testStreamLength();
}
void testStreamLength() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
stream = stream.take(5);
//统计事件的总数量
var allEvents = await stream.length;
print(allEvents);
}
8.stream.where
//stream_where.dart文件
import 'dart:async';
void main(){
//创建Stream,并按指定条件筛选出数据
testWhere();
}
void testWhere() async {
//时间间隔为1秒
Duration interval = Duration(seconds: 1);
//每隔1秒发送1次的事件流
Stream<int> stream = Stream.periodic(interval, (data) => data);
//筛选条件为返回值大于2的所有数据
stream = stream.where((data)=>data>2);
//筛选条件为返回值小于6的所有数据
stream = stream.where((data)=> data<6);
//最后取上面两件条件都满足的数据
await for(int i in stream){
print(i);
}
}
三、StreamController使用
上面直接创建流的方式在实际开发中用途不是很大,基本都是用StreamController来创建流
构建单订阅流
//stream_single.dart文件
import 'dart:async';
void main(){
//StreamController里面会创建一个Stream,我们实际操控的Stream
StreamController<String> streamController = StreamController();
//监听流数据
streamController.stream.listen((data)=> print(data));
//添加数据
streamController.sink.add("aaa");
//添加数据
streamController.add("bbb");
//添加数据
streamController.add("ccc");
//关闭流
streamController.close();
}
构建多订阅流
- 直接创建多订阅流
//stream_broadcast.dart文件
import 'dart:async';
void main(){
//使用StreamController的broadcast方法可以直接创建多订阅流
StreamController<String> streamController = StreamController.broadcast();
//第一个监听
streamController.stream.listen((data){
print('第一次的监听数据:'+ data);
},onError: (error){
print(error.toString());
});
//第一个监听
streamController.stream.listen((data){
print('第二次的监听数据:'+ data);
});
//添加数据
streamController.add("Dart...");
}
将单订阅流转化为多订阅流
//stream_as_broadcast.dart文件
import 'dart:async';
void main(){
//实例化StreamController对象
StreamController<String> streamController = StreamController();
//将单订阅流转换成多订阅流
Stream stream =streamController.stream.asBroadcastStream();
//添加第一次监听
stream.listen((data){
print('第一次的监听数据:'+ data);
});
//添加第二次监听
stream.listen((data){
print('第二次的监听数据:'+ data);
});
streamController.sink.add("Dart...");
//关闭流
streamController.close();
}
四、StreamBuilder
Futter里面提供了一个Widget名叫StreamBuilder其实是一直记录这流中最新的数据,当数据流发生变化时,会自动调用build方法重新渲染组件
//stream_stream_builder.dart文件
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StreamBuilder示例',
home: MyHomePage(),
);
}
}
//有状态组件
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//计数器值
int _count = 0;
//实例化一个StreamController对象
final StreamController<int> _streamController = StreamController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StreamBuilder示例'),
),
body: Container(
child: Center(
//StreamBuilder组件,数据类型为int
child: StreamBuilder<int>(
//指定stream属性
stream: _streamController.stream,
//构建器,可以通过AsyncSnapshot拿到流中的数据
builder: (BuildContext context, AsyncSnapshot snapshot) {
//这里不需要_count值,从流中取出data即可
return snapshot.data == null
? Text("0",style: TextStyle(fontSize: 36.0))
: Text("${snapshot.data}", style: TextStyle(fontSize: 36.0),
);
}),
),
),
//操作按钮
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: (){
//向Stream里添加数据
_streamController.sink.add(++_count);
}),
);
}
@override
void dispose() {
//当界面销毁时关闭Stream流
_streamController.close();
super.dispose();
}
}
响应式编程,Bloc解耦
//stream_bloc_base.dart文件
//定义Bloc抽象类
abstract class BlocBase {
//定义销毁方法,子类必需实现此方法
void dispose();
}
//stream_bloc_counter.dart文件
import 'dart:async';
import 'bloc_base.dart';
//继承BlocBase
class BlocCounter extends BlocBase {
//初例化StreamController,数据类型为int
final _controller = StreamController<int>();
//获取到StreamController的sink,即入口可以添加数据
get _counter => _controller.sink;
//获取到StreamController的stream,即出口可以取数据
get counter => _controller.stream;
//增加计算器值
void increment(int count) {
//向流中添加数据
_counter.add(++count);
}
//销毁
void dispose() {
//关闭流
_controller.close();
}
}
//stream_bloc_main.dart文件
import 'package:flutter/material.dart';
import 'blocs/bloc_counter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bloc示例',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState(BlocCounter());
}
class _MyHomePageState extends State<MyHomePage> {
//组件计数变量
int _counter = 0;
//计数器Bloc
final BlocCounter bloc;
_MyHomePageState(this.bloc);
//计数增加方法
void _incrementCounter() {
//调用bloc的方法
bloc.increment(_counter);
}
@override
void initState() {
//监听Bloc里的数据
bloc.counter.listen((_count) {
//设置状态值
setState(() {
_counter = _count;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bloc示例'),
),
body: Center(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
),
//增加按钮
floatingActionButton: FloatingActionButton(
//点击事件
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}