Asynchronous programming: Use stream
1.stream
What is the
A Stream is a sequence of asynchronous events.
2,Stream
The receiving
① Use asynchronous for loops
/// Use an asynchronous for loop to receive all streams
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for(var value in stream) {
sum += value;
}
return sum;
}
Copy the code
② Use stream listen to listen
3,stream
The type of
Single-subscription stream (single-subscription)
Contains only one sequence of events, which must be provided in sequence and cannot be lost. Like reading a file, receiving a web page.
② Broadcast stream
For a single message, one message at a time. Like the mouse event in the browser. You can listen at any time, you can add multiple listeners, and you can cancel them at any time.
4, processing,stream
The method of
Future<T> get first;
Future<bool> get isEmpty;
Future<T> get last;
Future<int> get length;
Future<T> get single;
Future<bool> any(bool Function(T element) test);
Future<bool> contains(Object? needle);
Future<E> drain<E>([E? futureValue]);
Future<T> elementAt(int index);
Future<bool> every(bool Function(T element) test);
Future<T> firstWhere(bool Function(T element) test, {T Function()? orElse});
Future<S> fold<S>(S initialValue, S Function(S previous, T element) combine);
Future forEach(void Function(T element) action);
Future<String> join([String separator = ' ']);
Future<T> lastWhere(bool Function(T element) test, {T Function()? orElse});
Future pipe(StreamConsumer<T> streamConsumer);
Future<T> reduce(T Function(T previous, T element) combine);
Future<T> singleWhere(bool Function(T element) test, {T Function()? orElse});
Future<List<T>> toList();
Future<Set<T>> toSet();
Copy the code
5, modify,stream
The method of
Modifying a stream creates a new stream, and listeners added to the original stream are transferred to the new stream or, if the new stream ends, to the original stream.
See article: Introduction to Flutter Stream and some of its operators
// Convert a Stream to a Stream with elements of type R
Stream<R> cast<R>();
// Convert each element in Stream to a sequence, such as element 1 to [1, 1].
Stream<S> expand<S>(可迭代<S> Function(T element) convert);
// Convert each element in the Stream to a new Stream according to the map implementation rules
Stream<S> map<S>(S Function(T event) convert);
// Skip the first count
Stream<T> skip(int count);
// Skip according to the passed condition rule
Stream<T> skipWhile(bool Function(T element) test);
// Specify that only count events are sent
Stream<T> take(int count);
// Only events with specified conditions are sent
Stream<T> takeWhile(bool Function(T element) test);
// Create a new Stream by conditionally discarding some elements
Stream<T> where(bool Function(T event) test); .Copy the code
6,listen
methods
StreamSubscription<T> listen(void onData(T event)? , {Function? onError, void onDone()? , bool? cancelOnError});Copy the code
7,stream
The creation of
① Convert the stream modification methods mentioned above from other streams
② Use async* to generate stream
Stream<int> createAsyncStream() async* {int num = 0; While (true) {// await future.delayed (Duration(seconds: 1)); // add num to stream yield num++; If (num == 10) break; }}Copy the code
③ Use StreamController to create
var streamController = StreamController<int>(
onListen: () {},
onResume: () {},
onPause: () {},
onCancel: () {},
);
Copy the code
For example, the implementation of event_bus uses a broadcast stream
EventBus({bool sync = false})
: _streamController = StreamController.broadcast(sync: sync);
Copy the code
8. Practical application scenarios
① Use of event_bus plug-in
Related articles: Analysis of Flutter EventBus usage and underlying implementation
- Initialize the
EventBus
, will create a broadcast initializationStreamController
.- Subscribe to listen,
on
The method returns astream
.stream
thelisten
Method that is passed in to handle a listener event.fire
Method is implemented by way ofStreamController
To add custom events.
② Use of Bloc plug-in
(3) StreamBuilder components
9, related syntax keywords (await, async, sync*, async*, yield, yield*)
① Await is used to wait for an asynchronous method to return data
② Async is used for asynchronous methods
Iterable
Iterable
④ Async * multielement async function generator, return Stream
⑤ Yield sends an element
⑥ Yield * operates on an Iterable or Stream
Specific usage examples are as follows:
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: StreamPage(), ); }}class StreamPage extends StatefulWidget {
const StreamPage({Key? key}) : super(key: key);
@override
_StreamPageState createState() => _StreamPageState();
}
class _StreamPageState extends State<StreamPage> {
late Stream<String> _stream;
@override
void initState() {
super.initState();
_stream = fetchEmojiStream(10);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Column(
children: [
MaterialButton(
onPressed: test1,
child: Text(Test '1'),
),
MaterialButton(
onPressed: test2,
child: Text('test 2'),
),
MaterialButton(
onPressed: test3,
child: Text('test 3'),
),
MaterialButton(
onPressed: test4,
child: Text('test 4'),
),
MaterialButton(
onPressed: test5,
child: Text('test 5'),
),
],
),
StreamBuilder(
stream: _stream,
builder: _builder,
),
],
),
);
}
Widget _builder(BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
break;
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.active:
return Text(snapshot.requireData);
case ConnectionState.done:
return Text(snapshot.requireData);
}
return Container();
}
void test1() async {
getEmoji(10).forEach(print);
/* flutter: 👿 flutter: 💀 flutter: 💁 flutter: 💂 flutter: 💀 flutter: Max flutter: Max flutter: Max flutter: Max flutter: Max flutter: Max flutter: Max flutter: Max 💈 * /
}
void test2() {
getEmojiWithTime(10).forEach(print);
/* Flutter: 👿-2021-09-02T16:41:24.557020 flutter: 💀-2021-09-02T16:41:24.558755 flutter: 💁-2021-09-02T16:41:24.559007 flutter: 💂-2021-09-02T16:41:24.559160 flutter: 💃-2021-09-02T16:41:24.559338 flutter: 💄-2021-09-02T16:41:24.559515 flutter: 💅-2021-09-02T16:41:24.559663 flutter: 💆-2021-09-02T16:41:24.559846 flutter: 💇 T16-2021-09-02: even. 560122 flutter: 💈 T16-2021-09-02: even. 560372 * /
}
void test3() {
fetchEmoji(0).then(print);
/ * flutter: 👿 * /
}
void test4() {
fetchEmojiStream(10).listen(print);
/* Every second a flutter is generated: 👿 flutter: 💀 flutter: 💁 flutter: 💂 flutter: 💀 flutter: festiveFlutter: festiveflutter: festiveFlutter: festiveFlutter: 💇 flutter: 💈 * /
}
void test5() {
fetchEmojiWithTime(10).forEach(print);
/* Flutter: 👿-2021-09-02T17:15:21.591821 flutter: 💀-2021-09-02T17:15:22.595980 flutter: 💁-2021-09-02T17:15:23.601100 flutter: 💂-2021-09-02T17:15:24.608355 flutter: 💃-2021-09-02T17:15:25.610364 flutter: 💄-2021-09-02T17:15:26.612006 Flutter: 💅-2021-09-02T17:15:27.619303 flutter: 💆-2021-09-02T17:15:28.623427 flutter: 💇 T17-2021-09-02: the days of. 626712 flutter: 💈 T17-2021-09-02:3:30. 629052 * /
}
/// Multielement synchronization
/// Multielement synchronization function generator (sync*), returns Iterable
/// Yield sends an element
可迭代<String> getEmoji(int count) sync* {
Runes first = Runes('\u{1f47f}');
for (int i = 0; i < count; i++) {
yield String.fromCharCodes(first.map((e) => e + i)); }}/// Multielement synchronization
/// Multielement synchronization generator (sync*), returns Iterable
/// yield* Operates on an Iterable
可迭代<String> getEmojiWithTime(int count) sync* {
yield* getEmoji(10).map((e) => '$e-${DateTime.now().toIso8601String()}');
}
/// Single element asynchrony
/// await async
Future<String> fetchEmoji(int count) async {
await Future.delayed(Duration(milliseconds: 1000));
return String.fromCharCodes(Runes('\u{1f47f}').map((e) => e + count));
}
/// Multielement asynchrony
/// Multielement async*), return Stream
/// Yield is an element
Stream<String> fetchEmojiStream(int count) async* {
for (int i = 0; i < count; i++) {
yield awaitfetchEmoji(i); }}/// Multielement asynchrony
/// Multielement async generator*), returns Stream
/// yield*We operate on a Stream
Stream<String> fetchEmojiWithTime(int count) async* {
yield* fetchEmojiStream(count).map((event) => '$event-${DateTime.now().toIso8601String()}'); }}Copy the code