主頁 > 軟體設計 > Android開發—Flutter 中的事件驅動【附:Flutter開發環境搭建和測驗全套PDF資料】

Android開發—Flutter 中的事件驅動【附:Flutter開發環境搭建和測驗全套PDF資料】

2021-06-14 07:29:42 軟體設計

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.OnClickListenerXML指定以外,通常是使用當前的Activity去實作View.OnClickListener介面,重寫onClick方法,根據ID來判斷點擊事件產生的物件,進而確定具體的點擊事件,

比如設定一個按鈕,我們點擊按鈕就要請求網路,那么點擊事件就會作為請求網路的驅動,這就是一個非常簡單的事件驅動的流程,

4. 事件驅動模型

事件驅動模型有三個要素:事件源監聽器事件,熟悉設計模式的同學應該很快就能反應過來,這三要素和Observer模式中的三個構成非常相似,實際上事件驅動模型就是基于觀察者而定制的,

事件驅動模型的作業步驟:

  1. 定義監聽器,為每一個事件撰寫處理方法,
  2. 監聽器物件注冊給事件源
  3. 事件源發生某個事件時,呼叫監聽器中對應的方法完成事件的處理,

以上的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將會自動地:

  1. 初始化2個FIFO佇列(MicroTask和Event)
  2. 并且當該方法執行完成后,執行Main方法
  3. 啟動事件回圈

事件回圈是一種無限回圈,在每個時鐘周期內,如果沒有其他的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

執行的流程:

  1. print(‘Before the Future’)
  2. 將 (){print(‘Running the Future’);} 添加到 Event 佇列;
  3. print(‘After the Future’)
  4. 事件回圈獲取(在第二步參考的)代碼并執行它
  5. 當代碼執行時,它會查找 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的事件處理規則執行,并不是真正的異步執行:

EvnetOfFlutter.png

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抓包新冠疫苗預約介面及腳本實作

下一篇:手把手教你調整電腦磁盤的磁區大小

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more