文檔參考 https://zhuanlan.zhihu.com/p/102193331
請直接參考原文
1.Dart中的..
表示什么意思?
Dart中的..
表示 級聯操作符
,為了方便配置而使用。..
和.
不同的是調用..
后返回的this.而.
返回的則是該方法的返回值。
2.Dart的作用域
Dart是沒有public
、private
關鍵字的,默認就是公開的,私有變量使用下劃線_開頭
3.Dart是不是單線程模型?是如何運行的?
-
Dart
是單線程模型。簡單來說,Dart在單線程中是以消息循環機制來運行的,包含兩個任務隊列。一個是微任務隊列microtask queue
,另一個叫做事件任務隊列event queue
。 - 當
flutter
啟動后,消息循環機制也啟動了。首先按照先進先出的順序逐個執行微任務隊列中的數據,當微任務隊列中的數據執行完成后便開始執行事件隊列中的任務,事件任務執行完畢后再去執行微任務,如此循環往復,直到兩個隊列中的任務都為空。 - 微任務隊列
(microtask queue)
,表示一個短時間內就會完成的異步任務。它的優先級最高,高于event queue
,只要隊列中還有任務,就可以一直霸占著事件循環。microtask queue
添加的任務主要是由 Dart內部產生。 - 事件隊列(
event queue
),包含所有的外來事件:I/O、mouse events、drawing events、timers、isolate之間的信息傳遞。 - 因為
microtask queue
的優先級高于event queue
,所以如果microtask queue
有太多的微任務, 那么就可能會霸占住當前的event loop
。從而對event queue
中的觸摸、繪制等外部事件造成阻塞卡頓。
4.Dart是如何實現多任務并行的
- Dart實現多任務并行主要依賴dart的并發編程、異步和驅動機制。
- 在dart中,一個
Isolate
對象其實就是一個Isolate
執行環境的引用,一般來說我們都是通過當前的Isolate
去控制其他的Isolate
完成彼此之間的交互,而當我們想要創建一個新的Isolate
可以使用Isolate.spawn
方法獲取一個新的Isolate
對象,兩個Isolate
之間使用SendPort
相互發送消息,而Isolate
中也存在了一個與之對應ReceivePort
接收消息用來處理,但是我們需要注意的是SendPort
和ReceivePort
在每一個Isolate
都有一對,只有同一個Isolate
中的ReceivePort
才能接受當前類的SendPort
發送的消息并且處理。
Isolate
可以把它理解為Dart中的線程。但它又不同于線程,更恰當的說應該是微線程。它與線程最大的區別就是不能共享內存,因此也不存在鎖競爭問題,兩個Isolate完全是兩條獨立的執行線,且每個Isolate都有自己的事件循環,它們之間只能通過發送消息通信,所以它的資源開銷低于線程。
5.說下Dart異步編程中的Future關鍵字?
在dart編程中,經常會使用Future來處理異步或者延時處理等任務操作。在dart的每一個isolate
中,執行的優先級為:Main-MicroTask-EventQueue
6.說下Dart異步編程中的Stream數據流
- 在 Flutter 中有兩種處理異步操作的方式 Future 和 Stream,Future 用于處理單個異步操作,Stream 用來處理連續的異步操作
- Stream 是一個抽象類,用于表示一序列異步數據的源。它是一種產生連續事件的方式,可以生成數據事件或者錯誤事件,以及流結束時的完成事件。
- 單訂閱流在發送完成事件之前只允許設置一個監聽器,并且只有在流上設置監聽器后才開始產生事件,取消監聽器后將停止發送事件。即使取消了第一個監聽器,也不允許在單訂閱流上設置其他的監聽器。廣播流則允許設置多個監聽器,也可以在取消上一個監聽器后再次添加新的監聽器。默認為單訂閱模式
- Stream 有同步流和異步流之分。它們的區別在于同步流會在執行 add,addError 或 close 方法時立即向流的監聽器 StreamSubscription 發送事件,而異步流總是在事件隊列中的代碼執行完成后在發送事件。`
7. await for如何使用?
await for
是用來不斷獲取stream流中的數據,然后執行循環體中的操作。它一般用在直到stream什么時候完成,并且必須等待傳遞完成后才能使用,不然會阻塞。
Stream<String> stream = new Stream<String>.fromIterable(['不開心', '面試', '沒', '過']);
main() async{
await for(String s in stream){
print(s);
}
}
8.說下mixin機制?
- dart為了支持多繼承引入
mixin
關鍵字。mixin定義的類不能有構造方法,這樣可以避免繼承多個類而產生的父類構造方法沖突。 -
mixins
對象是類,mixins絕不是繼承,也不是接口,而是一種全新的特性,可以mixins多個類,mixins使用需要滿足一定條件。
9.介紹下flutter框架,以及優缺點
google退出的跨平臺UI框架,可以快速在Android、ios上構建應用
優點
- 熱加載,保存后重載,模擬器立馬看見效果,相比原生編譯過程簡單
- 一切皆為組件,實現了富有感染力的靈活界面設計;
- 運行效率高
缺點
- 不支持熱更新
- Dart語言增加了學習難度
10.介紹下flutter的理念架構
flutter自下而上分為
Embedder
、Engine
、Framework
三層。
-
Embedder
是操作系統適配層,實現了渲染Surface
設置、線程設置,以及平臺插件等平臺相關特性的適配; -
Engine
層負責圖形繪制、文字排版和dart運行時。具有獨立虛擬機,正是由于他的存在,flutter可以運行在不同設備上 -
Framework
是dart編寫的基礎視圖庫,包含動畫、圖形、手勢等功能,使用頻率最高的一層
11.flutter的Engine
、Framework
作用
-
Framework
是dart編寫的框架,實現了一系列基礎庫,包含Material
和Cuptertino
風格的界面,還有就是動畫、繪制、手勢等等; -
Engine
層是Skia 2D
的繪圖引擎庫,其前身是個向量繪圖軟件,chrome
和android
均采用Skia
作為繪圖引擎層。skia
是跨平臺的,所以可以被嵌入到flutter的sdk中。android自帶skia
所以Flutter android SDK
比iOS sdk
小很多
12.介紹下Widget、State、Context概念
- Widget:在flutter'中一切皆為組件,可以將Widget想成一個可視化組件
- Widget樹:Widget以樹結構進行組織。包含父Widget、子Widget
- Context: Widget樹結構中某個Widget位置引用。一個context只屬于一個widget,他和widget一樣是鏈接在一起的,形成一個context樹
- State:定義了StatefulWidget實例的行為,用于交互、干預widget行為和布局
13.簡述StatelessWidget
和StatefulWidget
-
StatelessWidget
一旦創建就不關心任何變化,在下次構建前不會有任何變化。如Text
、Row
、Container
等。生命周期也簡單:初始化、build()渲染 -
StatefulWidget
生命周期內,該類所持有的數據可能會發生變化,這樣的數據被稱為State
。如復選框、button等等。State與Context關聯,并且關聯是永久性的,State對象將永遠不會改變其Context。當state與context關聯時,state被視為已掛載。
14.StatefulWidget
生命周期
-
initState()
: Widget初始化當前State,在當前方法中不能獲取到Context
的,如果想獲取,可以試試Future.delayed
-
didChageDependencies()
(1)initState()
后調用,(2)State對象依賴發生變化調用;系統語言、主題修改,系統也會通知調用 -
deactivate()
當State被暫時從視圖樹種移除時會調用,頁面切換時也會調用 -
despose()
Widget銷毀時調用 -
didUpdateWidget()
Widget狀態發生變化時調用,新舊Widget的key、runtimeType不變時調用。也就是Widget.canUpdate=>true. -
reassemble()
熱重載會被調用,在release下永遠不會被調用
創建并打開:initState->didChangeDependencies->build.
橫豎屏切換:didUpdateWidget->build 當前值保留
離開頁面:deactivate->dispose 重新進入init重新初始化
熱重載執行:reassemble->didUpdateWidget->build
調用setState->build
15.說下Widgets、RenderObjects和Elements的關系
-
Widget
:僅用于存儲渲染所需要的信息 -
renderObject
:負責管理布局、繪制等操作 -
Element
: 控制樹上的實體,管理底層渲染樹
Widget
會被inflate(填充)到Element
,并由Element
管理底層渲染樹。Widget
并不會直接管理狀態及渲染,而是通過state這個對象來管理狀態。flutetr創建Element
可見樹,相對于Widget
是可變的,通常用于開發中,我們不用操作Element
,而是由框架層實現內部邏輯。就如一個UI視圖樹中,可能包含多個TextWidget
,但是放在內部視圖樹的視角,這些TextWidget
都是填充到一個個獨立的Element
中。Element
會持有Widgets、RenderObjects
的實例。記住,Widget
只是一個配置,renderObject
負責管理布局、繪制等操作。
在第一個創建Widget
的時候,會對應創建一個Element
,然后將該元素插入到樹中。如果之后Widget
發生了變化,則將其與舊的Widget
進行比較,并且更新Element
。重要的事Element
不會被重建,只是更新而已。
16.什么是狀態管理,你了解那些狀態管理框架?
Flutter中的狀態和前端React中的狀態概念是一致的。React框架核心是組件化,應用由組件搭建而成,組件最重要的概念就是狀態,狀態是一個組件的UI數據模型,是組件渲染的數據依據。
Flutter的狀態分為全局狀態和局部狀態兩種。推薦使用Google退出的Provider
17.簡述Flutter的繪制流程
Flutter只關心向GPU(圖形處理器)提供視圖數據,GPU的vsync(垂直同步)信號同步到UI線程,UI線程使用dart來構建抽象的視圖結構,這份數據結構在GPU線程進行圖層合成。,這些數據提供給skia引擎渲染為GPU數據,這些數據通過openGL或者Vulkan提供給過給GPU
18.簡述Flutter的線程管理模型
- 默認情況下,Flutter Engine層會創建一個
lsolate
,并且Dart代碼默認運行在這個主lsolate
上。必要時可以使用spawnUrl
和spawn
兩種方式創建新的lsolate
,新創建的lsolate
由flutter進行統一的管理 - Flutter Engline自己不創建和管理線程,Flutter Engine線程的創建是由
Embeder
負責的。Embeder
指的是將引擎移植到平臺的中間層代碼。 - 在flutter架構中,
Embeder
提供四個Task Runner,每個Task Runner負責不同的任務,Flutter Engine不在乎Task Runner運行在哪個線程,但是它需要在線程整個生命周期中保持穩定。
19. Flutter是如何與原生Android、iOS進行通信的?
flutter 通過PlatformChannel與原生進行交互,其中PlatformChannel分為如下三種:
- BasicMessageChannel : 用于傳遞字符串及半結構化信息
- MethodChannel : 用于傳遞方法調用(method invocation)
- EnentChannel:用于數據流event streams的通信
同時 Platform Channel 并非是線程安全的
20.簡述Flutter的熱重載
- flutter的熱重載是基于JIT編譯模式的代碼增量同步。由于JIT屬于動態編譯,能夠將Dart代碼編程生成中間代碼,讓Dart VM在運行時解釋執行,因此可以實現動態更新中間代碼實現增量同步。
- 熱重載流程可以分為5步,包括:掃描工程改動、增量編譯、推送更新、代碼合并、Widget重建。flutter在接收到代碼后,并不會讓APP重新啟動執行,而只會副廠Widget樹的重新繪制,因此可以保持改動前狀態。
- 另一方面,由于涉及狀態的保存于恢復,涉及狀態兼容與狀態初始化場景,熱重載是無法支持的,如改動前后widget狀態無法兼容、全局變量與靜態屬性的更改、main方法里的更改、initState方法中的更改、枚舉和泛型的更改等
- 可以發現,熱重載提高了UI的效率,非常適合寫界面樣式這樣返回查看修改效果的場景。但由于狀態保存機制限制,熱重載本身有一些無法支持的邊界