1. 何謂驅動

百度百科告訴我們,驅動即用推動,事件驅動就是用一個個的事件,推動某個操作的執行,
2. Loop
在我們的Java編程的程式系列中,Android就是一個典型的事件驅動應用,熟悉Android開發的同學一定知道,其底層不斷地有一個Looper在回圈,遇到訊息則處理,否則阻塞在MessageQueue.next()方法處,我們非常常用的一個方法:runOnUiThread的作用是在主執行緒執行一個操作,因為在子執行緒安卓系統不允許我們操作UI,但是你想過他是如何實作的嗎?
其實很簡單:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
判斷一下當前執行緒是否主執行緒,是的話直接執行,否則的話,通過Handler機制,post到主執行緒,然后由子執行緒的Looper取出執行,
比如我們在請求網路后,想讓系統加載一個資料,資料回傳后,更新視圖,那么“資料回傳”實際上就是一個事件,既然是事件我們肯定要消費,所以就呼叫runOnUiThread交給主執行緒消費,
其實,我們在任何一個主執行緒的呼叫堆疊中,呼叫堆疊底的方法一定是loop方法,因為所有發生在主執行緒的操作都是先給主執行緒的MessageQueue加入一個Message,然后looper取出執行操作,Message甚至可以附帶一個Runnable來執行代碼,也可以附帶一些資訊,在回呼處統一處理,
3. OnClickListener 事件
我們通常會呼叫View下的setOnClickListener設定點擊事件,比較常見的寫法除了簡單的設定View.OnClickListener、XML指定以外,通常是使用當前的Activity去實作View.OnClickListener介面,重寫onClick方法,根據ID來判斷點擊事件產生的物件,進而確定具體的點擊事件,
比如設定一個按鈕,我們點擊按鈕就要請求網路,那么點擊事件就會作為請求網路的驅動,這就是一個非常簡單的事件驅動的流程,
4. 事件驅動模型
事件驅動模型有三個要素:事件源,監聽器,事件,熟悉設計模式的同學應該很快就能反應過來,這三要素和Observer模式中的三個構成非常相似,實際上事件驅動模型就是基于觀察者而定制的,
事件驅動模型的作業步驟:
- 定義
監聽器,為每一個事件撰寫處理方法, - 將
監聽器物件注冊給事件源 事件源發生某個事件時,呼叫監聽器中對應的方法完成事件的處理,
以上的3步,在OnClick事件中,分別對應:
//1\. 監聽器,處理回應事件
val events = View.OnClickListener {
Toast.makeText(this@MainActivity,"HelloWorld!",Toast.LENGTH_SHORT).show()
}
//2\. 注冊到事件源
findViewById<TextView>(R.id.tv).setOnClickListener (events)
//3\. 當我們手指點擊螢屏,產生事件時(即事件源產生事件),就向著目標分發事件,最終被觸摸到的View所消費,
5. Dart和Flutter
(這部分的內容主要來自淚已無痕:[譯] Flutter 異步編程:Future、Isolate 和事件回圈,原文更詳細,這里是完全參考著他寫的,詳細了解建議看原文,)
Dart是單執行緒模型,而Flutter則依賴于Dart,單執行緒模型有一個問題:同一時間執行一個操作,而其他的操作只能再其之后執行,
我們知道在Android中不能寫死回圈,否則會導致ANR,而Flutter也是一樣,在Dart中如果我們寫一個很大的for回圈,那么在回圈中執行操作同樣會導致執行緒的阻塞,界面也被阻塞,例如在重寫的setState()中執行回圈,則必須等到結束后才能加載出界面,
但是在如今紛繁復雜的業務邏輯要求中,我們單執行緒模型實際上很難滿足各種各樣的需求了,所以,Dart采用了了一個代碼序列器(事件回圈),
當我們啟動一個DartApp時,將會構建一個新的執行緒行程,在Dart中為Isolate,該執行緒將是你在整個應用中唯一需要關注的,
所以,此執行緒創建后,Dart將會自動地:
- 初始化2個FIFO佇列(MicroTask和Event)
- 并且當該方法執行完成后,執行Main方法
- 啟動
事件回圈
事件回圈是一種無限回圈,在每個時鐘周期內,如果沒有其他的Dart代碼執行,則:
void eventLoop(){
while (microTaskQueue.isNotEmpty){
fetchFirstMicroTaskFromQueue();
executeThisMicroTask();
return;
}
if (eventQueue.isNotEmpty){
fetchFirstEventFromQueue();
executeThisEventRelatedCode();
}
}
從先后順序我們可以看出,MicoTask佇列優先于Event佇列,
5.1 MicroTask佇列
MicroTask佇列用于非常簡短且需要異步執行的的內部動作,這些動作需要在其他事件完成后 并 在將執行權交給Event佇列之前運行,
5.2 Event佇列
Event 佇列適用于以下參考模型:
- IO
- 手勢
- 繪圖
- 計時器
- 流
- futures
事實上,每次外部事件被觸發時,需要執行的代碼都會被Event佇列所參考,一旦沒有MicroTask運行,事件回圈將考慮Event佇列中的第一項并執行它,而Future操作也將由Event佇列執行,
5.3 Future
Future是一個異步執行并且在未來某一個時刻完成或者失敗的任務,當實體化一個Future時:
- 該Future的實體被創建、并記錄在由Dart管理的內部陣列中,
- 需要由此Future執行的代碼直接推送到Event中,
- 該Future實體回傳一個狀態(=incomplete)
- 如果存在下一個同步代碼,則執行它,
只要事件回圈從Event回圈中獲取它,被Future參考的代碼將像其他任何Event一樣執行,
當改代碼將被執行完成(或者失敗)時,then或者cacheError回呼將被觸發,
在如下例子中:
void main(){
print('Before the Future');
Future((){
print('Running the Future');
}).then((_){
print('Future is complete');
});
print('After the Future');
}
輸出的順序:
Before the Future
After the Future
Running the Future
Future is complete
執行的流程:
- print(‘Before the Future’)
- 將 (){print(‘Running the Future’);} 添加到 Event 佇列;
- print(‘After the Future’)
- 事件回圈獲取(在第二步參考的)代碼并執行它
- 當代碼執行時,它會查找 then() 陳述句并執行它
所以,Flutter/Dart是使用Event回圈機制來模擬并發的請求的,
Aysnc方法在使用時,Dart會認為該方法的回傳值是一個Future,它同步執行該方法,直到遇到第一個await關鍵字,然后它暫停該方法其他部分的執行,一旦await關鍵字參考的Future執行完成,下一行代碼將立即執行,
例如這個例子:
void main() async {
methodA();
await methodB();
await methodC('main');
methodD();
}
methodA(){
print('A');
}
methodB() async {
print('B start');
await methodC('B');
print('B end');
}
methodC(String from) async {
print('C start from $from');
Future((){ // <== 該代碼將在未來的某個時間段執行
print('C running Future from $from');
}).then((_){
print('C end of Future from $from');
});
print('C end from $from');
}
methodD(){
print('D');
}
從Main方法開始執行,遇到第一個await則暫停,按照以往的認知,列印應該是:
A
B start
C start from B
C running Future from B
C end of Future from B
C end from B
B end
C start from A
C running Future from A
C end of Future from A
C end from A
D
但是其實是:
A
B start
C start from B
C end from B
--- C中的Future代碼會在之后執行,不會立即執行,
B end
C start from main
C end from main
D
---到此處代碼執行完了,才開始執行Event中的代碼
C running Future from B
C end of Future from B
C running Future from main
C end of Future from main
這和我們想象的多執行緒(異步)處理有點不一樣,異步只是執行緒各自以未知的順序向前推進,但是單執行緒的Dart依靠事件回圈機制,模擬了異步操作,但是我們發現所有的Future都放到了代碼的最后執行,預測程式執行變得非常困難,
我們又知道,await會阻塞在當前代碼的位置,所以,await和Future配合使用,可以獲得同步的效果,即該代碼等到Future執行完了再向下執行:
methodC(String from) async {
print('C start from $from');
await Future((){ // <== 在此處進行修改
print('C running Future from $from');
}).then((_){
print('C end of Future from $from');
});
print('C end from $from');
}
這樣一來,可能在C start之后,等到C執行完成再向下執行,
所以,Dart中的異步執行實際上只是按照Event的事件處理規則執行,并不是真正的異步執行:

5.4 Isolate
那么Flutter/Dart有自己的執行緒嗎?Isolate,
Isolate在Flutter中不共享記憶體,不同的Isolate之間通過訊息進行通信,
而每個Isolate都有自己的事件回圈及佇列(MicroTask和Event),這就意味著一個Isolate中運行的代碼和另外一個Isolate不存在任何的關聯,
是不是有點像Loop,
5.4.1 如何啟用Isolate呢?
我們需要在呼叫者和新的Isolate之間建立通信,
每個Isolate都暴露了一個將訊息傳遞給Isolate的被稱為SendPort的埠(這是一個監聽埠,不是用來發送的),
這意味著呼叫者和new Isolate需要知道彼此的埠才能進行通信,
我們有了埠就能發送訊息,最后記得在dispose中銷毀即可,
這是一種單工的通信方式(單監聽流),我們只能從一方聽到另一方發送的訊息,如果要實作雙工的通信需要彼此之間建立兩條監聽流,
5.5 結論
Flutter的事件回圈機制有點像Android執行緒的Looper,但是Dart是單執行緒的,而Future和Isolate則可以實作或者是模擬異步操作,在開發中有非常重要的作用,
最后
Flutter學習進階——開發環境搭建和測驗
每一個移動開發者都在為 Flutter 帶來的“快速開發、富有表現力和靈活的 UI、原生性能”的特色和理念而癡狂,從超級 App 到獨立應用,從純 Flutter 到混合堆疊,開發者們在不同的場景下樂此不疲的探索和應用著 Flutter 技術,也在面臨著各種各樣不同的挑戰,
本篇知識要點:
- 1、Flutter跨平臺開發概述
- 2、Windows中Flutter開發環境搭建
- 3、撰寫你的第一個Flutter APP
- 4、Flutter Dart語言系統入門

完整學習筆記pdf免費分享,需要的朋友只需要點贊支持一下后,【點擊這里直達免費獲取方式】
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/287189.html
標籤:其他
上一篇:【新冠疫苗預約】Fiddler抓包新冠疫苗預約介面及腳本實作
下一篇:手把手教你調整電腦磁盤的磁區大小
