Flutter 假異步的實(shí)現(xiàn)示例
就像 android 有 handle 一樣,消息隊(duì)列這東西好像還真是系統(tǒng)必備,F(xiàn)lutter 也有自己的消息隊(duì)列,只不過(guò)隊(duì)列直接封裝在了 Dart 的線程類型 Isolate 里面了,不過(guò) Flutter 還是提供了 Futrue 這個(gè) API 來(lái)專門來(lái)操作各種消息,以及實(shí)現(xiàn)基于消息隊(duì)列的假異步
Flutter 的“異步”機(jī)制
這里的異步是加了引號(hào)的,可見(jiàn)此異步非真異步,而是假異步。Flutter 的 異步 不是開(kāi)新線程,而是往所屬線程的 消息隊(duì)列 中添加任務(wù),當(dāng)然大家也可以按上文那樣自己展開(kāi)真異步操作
Flutter 對(duì)代碼分2類: 同步代碼和異步代碼
- 同步代碼:傳統(tǒng)一行行寫下來(lái),一行行執(zhí)行的代碼
- 異步代碼:通過(guò) Future API 把任務(wù)添加到 Isolate 所屬消息隊(duì)列執(zhí)行的偽異步
- 執(zhí)行順序:先運(yùn)行同步代碼,再運(yùn)行異步代碼
為啥,很明顯啊,異步代碼是往消息隊(duì)列里添加任務(wù),那肯定得等現(xiàn)在的代碼運(yùn)行完了,線程有空閑了才能開(kāi)始執(zhí)行消息隊(duì)列里的任務(wù)呀~
舉個(gè)例子:
void test() {
print("AA");
Future(() => print("Futrue"));
print("BB");
}
~~~~~~~~~~~log~~~~~~~~~~~~~
I/flutter (10064): AA
I/flutter (10064): BB
I/flutter (10064): Futrue
print("Futrue")) 任務(wù)等到最后才執(zhí)行的...
Flutter 提供了往 消息隊(duì)列 添加數(shù)據(jù)的 API: Future
往 MicroTask 隊(duì)列添加任務(wù)
scheduleMicrotask((){
// ...code goes here...
});
new Future.microtask((){
// ...code goes here...
});
往 Event 隊(duì)列添加任務(wù)
new Future(() {
// ...code goes here...
});
Future 的基本使用
Future 對(duì)象是 Flutter 專門提供的,基于消息隊(duì)列實(shí)現(xiàn)異步的類,F(xiàn)uture 對(duì)象會(huì)把自身當(dāng)做一個(gè)任務(wù)添加到消息隊(duì)列中去排隊(duì)執(zhí)行
Future 對(duì)象接受的是一個(gè)函數(shù),就是要執(zhí)行的任務(wù),用 () => ... 簡(jiǎn)寫也是可以的
void task() {
print("AA");
}
var futrue = Future(task);
創(chuàng)建 Future 任務(wù)方式:
- Future()
- Future.microtask()
- Future.sync() - 同步任務(wù)
- Future.value()
- Future.delayed() - 延遲xx時(shí)間添加任務(wù)
- Future.error() - 錯(cuò)誤處理
我們來(lái)看幾個(gè)代表性的:
Future.sync() - 阻塞任務(wù),會(huì)阻塞當(dāng)前代碼,sync 的任務(wù)執(zhí)行完了,代碼才能走到下一行
void test() {
print("AA");
Future.sync(() => print("Futrue"));
print("BB");
}
~~~~~~~~~~~~log~~~~~~~~~~~~~~
I/flutter (10573): AA
I/flutter (10573): Futrue
I/flutter (10573): BB
Future.delayed() - 延遲任務(wù),指定xx時(shí)間后把任務(wù)添加到消息隊(duì)列,要是消息隊(duì)列前面有人執(zhí)行的時(shí)間太長(zhǎng)了,那么執(zhí)行時(shí)間點(diǎn)就不能把握了,這點(diǎn)大家要知道
void test() {
print("AA");
Future.delayed(Duration(milliseconds: 500),() => print("Futrue"));
print("BB");
}
~~~~~~~~~~~~log~~~~~~~~~~~~~~
I/flutter (10573): AA
I/flutter (10573): BB
I/flutter (10573): Futrue
Future 的鏈?zhǔn)秸{(diào)用
Future 也支持鏈?zhǔn)秸{(diào)用的,在 API 使用上也是很靈活的,提供了下面的選擇給大家
.then - 在 Future 執(zhí)行完后執(zhí)行,相當(dāng)于一個(gè) callback,而不是重新創(chuàng)建了一個(gè) Future
Future.delayed(Duration(seconds: 1),(){
print(("AAA"));
return "AA";
}).then((value){
print(value);
});
.catchError - future 不管在任何位置發(fā)生了錯(cuò)誤,都會(huì)立即執(zhí)行 catchError
Future.delayed(Duration(seconds: 1),(){
throw Exception("AAA");
}).then((value){
print(value);
}).catchError((error){
print(error);
});
.whenComplete - 不管是否發(fā)生異常,在執(zhí)行完成后,都會(huì)執(zhí)行該方法
Future.delayed(Duration(seconds: 1), () {
throw Exception("AAA");
}).then((value) {
print(value);
}).catchError((error) {
print(error);
}).whenComplete(() {
print("complete...");
});
.wait - 可以等待所有的 future 都執(zhí)行完畢再走 then 的方法
Future.wait([
// 2秒后返回結(jié)果
Future.delayed(new Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回結(jié)果
Future.delayed(new Duration(seconds: 4), () {
return " world";
})
]).then((results) {
print(results[0] + results[1]);
}).catchError((e) {
print(e);
});
大家想想啊
Futrue() .then() .then() ...
這樣的鏈?zhǔn)綄懛ú痪褪菢?biāo)準(zhǔn)的去 callback 回調(diào)地獄的方式嘛
async/await 關(guān)鍵字
async/await 這組關(guān)鍵字是系統(tǒng)提供的另一種實(shí)現(xiàn) 異步 任務(wù)的 API, async/await 底層還是用 Futrue 實(shí)現(xiàn)的,從使用上看是對(duì) Futrue 的簡(jiǎn)化,本質(zhì)上還是基于 消息隊(duì)列 實(shí)現(xiàn)的異步,是 假異步 ,和 Isoalte 是不一樣的
async/await 的特點(diǎn)就是: 成對(duì)出現(xiàn)
- async - 修飾方法,用 async 聲明的方法都是耗時(shí)的
- await - 調(diào)用 async 方法時(shí)使用,也可以在 async 方法內(nèi)部是適用,await 表示阻塞,下面的任務(wù)必須等 await 調(diào)用的方法執(zhí)行完之后才能執(zhí)行
比如這樣:
anysncTest() async {
print("async 休眠 start...");
sleep(Duration(seconds: 1));
print("async 休眠 end...");
}
await anysncTest();
本質(zhì)上 await 調(diào)用的方法其實(shí)是把這個(gè)方法包裝到 Futrue 中去消息隊(duì)列里執(zhí)行,只不過(guò)是: Future.sync() 阻塞式的 Future 任務(wù)
這 async 在布局中也是可以直接用的
class TestWidgetState extends State<TestWidget> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Material(
FlatButton(
onPressed: () async {
_count = countEven(1000000000);
setState(() {});
},
child: Text(
_count.toString(),
)),
);
}
async/await 是阻塞式的函數(shù)
實(shí)驗(yàn)1:
// 這是異步任務(wù)代碼
aaa() async{
print("main1...");
await anysncTest();
print("main2...");
print("main3...");
}
anysncTest() async {
print("async 休眠 start...");
sleep(Duration(seconds: 1));
print("async 休眠 end...");
}
// 點(diǎn)擊按鈕去執(zhí)行
Widget build(BuildContext context) {
return RaisedButton(
child: (Text("click!")),
onPressed: () async {
await aaa();
},
);
}
可以看到 async/await
執(zhí)行的方法的確是阻塞時(shí)的,至少在這個(gè) async 方法里絕對(duì)是阻塞式的
實(shí)驗(yàn)2:
那么范圍擴(kuò)展一下,在 async 外面再來(lái)看看 async/await 是不是阻塞式的? 有人說(shuō) async/await 和協(xié)程一樣 ,協(xié)程的關(guān)鍵點(diǎn)在于非競(jìng)爭(zhēng)式資源,協(xié)程的概念中,當(dāng)多個(gè)協(xié)程中有一個(gè)協(xié)程掛起之后,并不會(huì)阻塞 CPU,CPU 回去執(zhí)行其他協(xié)程方法,直到有空閑了再來(lái)執(zhí)行之前掛起后恢復(fù)的協(xié)程,雖然在協(xié)程看來(lái)我掛起了線程,但其實(shí) CPU 不會(huì)被協(xié)程掛起阻塞,這點(diǎn)就是協(xié)程的核心優(yōu)勢(shì),大大提升多線程下的執(zhí)行效率。
從這點(diǎn)出發(fā)我們就能知道 async/await 是不是又一個(gè)協(xié)程了,看看他阻塞 CPU,我們?cè)?await 之后看看 async 后面的代碼會(huì)不會(huì)執(zhí)行就 OK了
// 還是這組方法
aaa() async{
print("main1...");
await anysncTest();
print("main2...");
print("main3...");
}
anysncTest() async {
print("async 休眠 start...");
sleep(Duration(seconds: 1));
print("async 休眠 end...");
}
// 執(zhí)行,注意此時(shí)按鈕的點(diǎn)擊方法不是 async 的
Widget build(BuildContext context) {
return RaisedButton(
child: (Text("click!")),
onPressed: () {
print("click1...");
aaa();
print("click2...");
print("click3...");
},
);
}
I/flutter ( 5733): click1... I/flutter ( 5733): main1... I/flutter ( 5733): async 休眠 start... I/flutter ( 5733): async 休眠 end... I/flutter ( 5733): click2... I/flutter ( 5733): click3... I/flutter ( 5733): main2... I/flutter ( 5733): main3...
await 阻塞是真的阻塞 CPU 了,所以 async/await 不是協(xié)程,但是大家注意啊,在 await 結(jié)速阻塞之后執(zhí)行的是 click2 也就是 async 外部的方法,說(shuō)明 await 標(biāo)記的方法返回的都是 Futrue 對(duì)象的說(shuō)法是正確的,隊(duì)列只有在線程空閑時(shí)才會(huì)執(zhí)行,顯然此時(shí)線程不是空閑的,點(diǎn)擊方法還沒(méi)執(zhí)行完呢
實(shí)驗(yàn)3:
這次做對(duì)比實(shí)驗(yàn),把點(diǎn)擊事件也變成 async 的看看執(zhí)行順序
// 還是這組方法
aaa() async{
print("main1...");
await anysncTest();
print("main2...");
print("main3...");
}
anysncTest() async {
print("async 休眠 start...");
sleep(Duration(seconds: 1));
print("async 休眠 end...");
}
// 執(zhí)行
Widget build(BuildContext context) {
return RaisedButton(
child: (Text("click!")),
onPressed: () async {
print("click1...");
await aaa();
print("click2...");
print("click3...");
},
);
}
I/flutter ( 5733): click1... I/flutter ( 5733): main1... I/flutter ( 5733): async 休眠 start... I/flutter ( 5733): async 休眠 end... I/flutter ( 5733): main2... I/flutter ( 5733): main3... I/flutter ( 5733): click2... I/flutter ( 5733): click3...
這樣看的話在 async 方法內(nèi)部,是嚴(yán)格按照順序執(zhí)行的
async 方法的格式
1. async 標(biāo)記的方法返回值都是 Futrue 類型的
上文書哦說(shuō) await 調(diào)用的方法返回的都是 Futrue 對(duì)象,那么就是說(shuō)在聲明 async 函數(shù)時(shí),返回值都是 Futrue 類型的,F(xiàn)utrue 內(nèi)部包裹實(shí)際的返回值類型
Futrue<String> getData() async {
data = await http.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
}
Futrue<String> 我們可以不寫,dart 也會(huì)自動(dòng)推斷出來(lái),但是我們一定要知道是 Futrue 類型的,要不有時(shí)會(huì)報(bào)類型錯(cuò)誤
我們?cè)谟玫臅r(shí)候都是配合 await 使用的,這時(shí)候可以直接用具體類型值接返回值了
String data = await getData();
記?。?/p>
Future就是event,很多Flutter內(nèi)置的組件比如前幾篇用到的Http(http請(qǐng)求控件)的get函數(shù)、RefreshIndicator(下拉手勢(shì)刷新控件)的onRefresh函數(shù)都是event。每一個(gè)被await標(biāo)記的句柄也是一個(gè)event,每創(chuàng)建一個(gè)Future就會(huì)把這個(gè)Future扔進(jìn)event queue中排隊(duì)等候安檢~
Stream
Stream 和 Future 一樣都是假異步操作,區(qū)別是 Stream 可以接受多次數(shù)據(jù),我不詳細(xì)展開(kāi)了,有待以后詳細(xì)研究
Stream.fromFutures([
// 1秒后返回結(jié)果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 拋出一個(gè)異常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回結(jié)果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:Android實(shí)現(xiàn)WIFI和GPRS網(wǎng)絡(luò)的切換
欄 目:Android
下一篇:android 使用kotlin 實(shí)現(xiàn)點(diǎn)擊更換全局語(yǔ)言(中日英切換)
本文標(biāo)題:Flutter 假異步的實(shí)現(xiàn)示例
本文地址:http://www.jygsgssxh.com/a1/Android/9116.html
您可能感興趣的文章
- 01-10如何給Flutter界面切換實(shí)現(xiàn)點(diǎn)特效
- 01-10android異步消息機(jī)制 源碼層面徹底解析(1)
- 01-10android異步消息機(jī)制 從源碼層面解析(2)
- 01-10Flutter適配深色模式的方法(DarkMode)
- 01-10Flutter 滾動(dòng)監(jiān)聽(tīng)及實(shí)戰(zhàn)appBar滾動(dòng)漸變的實(shí)現(xiàn)
- 01-10Flutter里面錯(cuò)誤捕獲的正確方法
- 01-10如何使用Flutter實(shí)現(xiàn)58同城中的加載動(dòng)畫詳解
- 01-10使用Flutter實(shí)現(xiàn)一個(gè)走馬燈布局的示例代碼
- 01-10Flutter中如何加載并預(yù)覽本地的html文件的方法
- 01-10flutter 中監(jiān)聽(tīng)滑動(dòng)事件


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方
- 01-10android實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 01-10android實(shí)現(xiàn)記住用戶名和密碼以及自動(dòng)
- 01-10C++自定義API函數(shù)實(shí)現(xiàn)大數(shù)相乘算法
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10如何給Flutter界面切換實(shí)現(xiàn)點(diǎn)特效
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10Emoji表情在Android JNI中的兼容性問(wèn)題詳
隨機(jī)閱讀
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開(kāi)原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改


