前言
類別 | 關鍵字 | 返回型別 | 搭檔 |
---|---|---|---|
多元素同步 | sync* | Iterable<T> |
yield、yield* |
單元素非同步 | async | Future<T> |
await |
多元素非同步 | async* | Stream<T> |
yield、yield* 、await |
下面就用幾個emoji,認識一下這幾個關鍵字吧
一、多元素同步函式生成器
1. sync*
和 yield
sync*
是一個dart語法關鍵字
。它標註在函式{ 之前,其方法必須返回一個 Iterable<T>物件
? 的碼為\u{1f47f}
。下面是使用sync*
生成後10個emoji迭代(Iterable)物件
的方法
main() {
getEmoji(10).forEach(print);
}
Iterable<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));
}
}
複製程式碼
?
?
?
?
?
?
?
?
?
?
複製程式碼
2、sync*
和 yield*
yield*
又是何許人也? 記住一點yield*
後面的表示式是一個Iterable<T>物件
比如下面getEmoji
方法是核心,現在想要列印每次的時間,使用getEmojiWithTime
yield*
之後的getEmoji(count).map((e)...
便是一個可迭代物件Iterable<String>
main() {
getEmojiWithTime(10).forEach(print);
}
Iterable<String> getEmojiWithTime(int count) sync* {
yield* getEmoji(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}
Iterable<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));
}
}
複製程式碼
? -- 2020-05-20T07:01:07.163407
? -- 2020-05-20T07:01:07.169451
? -- 2020-05-20T07:01:07.169612
? -- 2020-05-20T07:01:07.169676
? -- 2020-05-20T07:01:07.169712
? -- 2020-05-20T07:01:07.169737
? -- 2020-05-20T07:01:07.169760
? -- 2020-05-20T07:01:07.169789
? -- 2020-05-20T07:01:07.169812
? -- 2020-05-20T07:01:07.169832
複製程式碼
二、非同步處理: async
和await
async
是一個dart語法關鍵字
。它標註在函式{ 之前,其方法必須返回一個 Future<T>物件
對於耗時操作,通常用Future<T>
物件非同步處理,下面fetchEmoji方法
模擬2s載入耗時
main() {
print('程式開啟--${DateTime.now().toIso8601String()}');
fetchEmoji(1).then(print);
}
Future<String> fetchEmoji(int count) async{
Runes first = Runes('\u{1f47f}');
await Future.delayed(Duration(seconds: 2));//模擬耗時
print('載入結束--${DateTime.now().toIso8601String()}');
return String.fromCharCodes(first.map((e) => e + count));
}
複製程式碼
載入開始--2020-05-20T07:20:32.156074
載入結束--2020-05-20T07:20:34.175806
?
複製程式碼
三、多元素非同步函式生成器:
1.async*
和yield
、await
async*
是一個dart語法關鍵字
。它標註在函式{ 之前,其方法必須返回一個 Stream<T>物件
下面fetchEmojis
被async*
標註,所以返回的必然是Stream
物件
注意被async*
標註的函式,可以在其內部使用yield、yield*、await
關鍵字
main() {
fetchEmojis(10).listen(print);
}
Stream<String> fetchEmojis(int count) async*{
for (int i = 0; i < count; i++) {
yield await fetchEmoji(i);
}
}
Future<String> fetchEmoji(int count) async{
Runes first = Runes('\u{1f47f}');
print('載入開始--${DateTime.now().toIso8601String()}');
await Future.delayed(Duration(seconds: 2));//模擬耗時
print('載入結束--${DateTime.now().toIso8601String()}');
return String.fromCharCodes(first.map((e) => e + count));
}
複製程式碼
載入開始--2020-05-20T07:28:28.394205
載入結束--2020-05-20T07:28:30.409498
?
載入開始--2020-05-20T07:28:30.416714
載入結束--2020-05-20T07:28:32.419157
?
載入開始--2020-05-20T07:28:32.419388
載入結束--2020-05-20T07:28:34.423053
?
載入開始--2020-05-20T07:28:34.423284
載入結束--2020-05-20T07:28:36.428161
?
載入開始--2020-05-20T07:28:36.428393
載入結束--2020-05-20T07:28:38.433409
?
載入開始--2020-05-20T07:28:38.433647
載入結束--2020-05-20T07:28:40.436491
?
載入開始--2020-05-20T07:28:40.436734
載入結束--2020-05-20T07:28:42.440696
?
載入開始--2020-05-20T07:28:42.441255
載入結束--2020-05-20T07:28:44.445558
?
載入開始--2020-05-20T07:28:44.445801
載入結束--2020-05-20T07:28:46.448190
?
載入開始--2020-05-20T07:28:46.448432
載入結束--2020-05-20T07:28:48.452624
?
複製程式碼
2.async*
和yield*
、await
和上面的
yield*
同理,async*
方法內使用yield*
,其後物件必須是Stream<T>
物件
如下getEmojiWithTime
對fetchEmojis
流進行map轉換,前面需要加yield*
main() {
getEmojiWithTime(10).listen(print);
}
Stream<String> getEmojiWithTime(int count) async* {
yield* fetchEmojis(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}
Stream<String> fetchEmojis(int count) async*{
for (int i = 0; i < count; i++) {
yield await fetchEmoji(i);
}
}
Future<String> fetchEmoji(int count) async{
Runes first = Runes('\u{1f47f}');
await Future.delayed(Duration(seconds: 2));//模擬耗時
return String.fromCharCodes(first.map((e) => e + count));
}
複製程式碼
? -- 2020-05-20T07:35:09.461624
? -- 2020-05-20T07:35:11.471223
? -- 2020-05-20T07:35:13.476712
? -- 2020-05-20T07:35:15.482848
? -- 2020-05-20T07:35:17.489429
? -- 2020-05-20T07:35:19.491214
? -- 2020-05-20T07:35:21.497086
? -- 2020-05-20T07:35:23.500867
? -- 2020-05-20T07:35:25.505379
? -- 2020-05-20T07:35:27.511723
複製程式碼
四、Stream的使用-StreamBuilder
Stream在元件層面最常用的就數
StreamBuilder
,本文只是簡單用一下,以後會有專文
StreamBuilder
元件使用的核心就是,它接受一個Stream物件
,
根據builder函式
在流元素的不同狀態下構建不同的介面。
1.頂部元件
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: Scaffold(
appBar: AppBar(),
body: HomePage(),
));
}
}
複製程式碼
2.StreamBuilder元件的使用
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Stream<String> _stream;
@override
void initState() {
super.initState();
_stream= fetchEmojis(10);
}
@override
Widget build(BuildContext context) {
return Center(
child: StreamBuilder<String>(
builder: _buildChildByStream,
stream: _stream,
),
);
}
Widget _buildChildByStream(
BuildContext context, AsyncSnapshot<String> snapshot) {
switch(snapshot.connectionState){
case ConnectionState.none:
break;
case ConnectionState.waiting:
return CircularProgressIndicator();
break;
case ConnectionState.active:
return Text(snapshot.requireData,style: TextStyle(fontSize: 60));
break;
case ConnectionState.done:
return Text('Stream Over--${snapshot.requireData}',style: TextStyle(fontSize: 30),);
break;
}
return Container();
}
Stream<String> fetchEmojis(int count) async* {
for (int i = 0; i < count; i++) {
yield await fetchEmoji(i);
}
}
Future<String> fetchEmoji(int count) async {
Runes first = Runes('\u{1f47f}');
await Future.delayed(Duration(seconds: 1)); //模擬耗時
return String.fromCharCodes(first.map((e) => e + count));
}
}
複製程式碼
題外話:
如果你使用過
flutter_bloc
,會用到async*
,現在再來看,是不是更清楚了一點。
class CounterBloc extends Bloc<CounterEvent, int> {
@override
int get initialState => 0;
@override
Stream<int> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.decrement:
yield state - 1;
break;
case CounterEvent.increment:
yield state + 1;
break;
}
}
}
複製程式碼
尾聲
歡迎Star和關注FlutterUnit 的發展,讓我們一起攜手,成為Unit一員。
另外本人有一個Flutter微信交流群,歡迎小夥伴加入,共同分享Flutter的知識,期待與你的交流與切磋。
@張風捷特烈 2020.05.20 未允禁轉
我的公眾號:程式設計之王
聯絡我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~