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


閱讀排行
本欄相關
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實現(xiàn)雙擊返回鍵退出應用實現(xiàn)方
- 01-10android實現(xiàn)簡單計算器功能
- 01-10android實現(xiàn)記住用戶名和密碼以及自動
- 01-10C++自定義API函數(shù)實現(xiàn)大數(shù)相乘算法
- 01-10Android 友盟第三方登錄與分享的實現(xiàn)代
- 01-10android實現(xiàn)指紋識別功能
- 01-10如何給Flutter界面切換實現(xiàn)點特效
- 01-10Android實現(xiàn)圓形漸變加載進度條
- 01-10Emoji表情在Android JNI中的兼容性問題詳
隨機閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-10C#中split用法實例總結
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改