一、flutter啟動流程
1.實例化WidgetsFlutterBinding類,
2.創(chuàng)建組件樹attachRootWidget(app),
3.啟動預熱幀scheduleWarnUpFrame()。
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
1.WidgetsFlutterBinding類繼承自BindingBase基類和其它一些特定功能特性類,該類是將基于組件框架的應用程序綁定到Flutter引擎的膠水類,并返回一個WidgetsBinding實例。
BindingBase: 該類是一個抽象類基類,初始化拓展服務,其申明的接口由其子類實現(xiàn)。
-GestureBinding: 該類綁定了手勢事件,用于檢測應用程序各類手勢。它以mixin的方式加入到WidgetsFlutterBinding中,并實現(xiàn)了BindingBase類中的部分方法。
-ServicesBinding:該類監(jiān)聽了平臺消息(platform messages),注冊了Flutter層與Native層的消息傳輸服務,最終將消息定向到BinaryMessages類中。
-SchedulerBinding: 該類注冊了頁面幀繪制有關的回調函數(shù),同時也處理Widget生命周期相關事件,處理的事件類型包括:paused、resumed、inactive和suspending。
-PaintingBinding:綁定繪制庫,同時還創(chuàng)建了圖片緩存。
-SemanticsBinding:將組件語義樹與Flutter引擎綁定
-RendererBinding:將組件渲染樹與Flutter引擎綁定
-WidgetsBinding:將組件樹與Flutter引擎綁定
2.attachRootWidget(Widget rootWidget)函數(shù)
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement);
}
該函數(shù)調用RenderObjectToWidgetAdapter函數(shù)創(chuàng)建了一個RenderBox,緊接著將改組件作為根節(jié)點并調用attachToRenderTree把組件綁定到Widget樹中。
3.scheduleForcedFrame()函數(shù)
該函數(shù)作用是在App啟動是盡快運行預熱幀,而不是等待引擎請求幀以響應系統(tǒng)“Vsync”信號。
二、異步
可以使我們在編寫Dart程序時可以異步的來執(zhí)行耗時操作。從而可以在等待一個操作完成的同時進行別的操作以下是一些常見的異步操作:
通過網(wǎng)絡獲取數(shù)據(jù)。
寫入數(shù)據(jù)庫。
從文件讀取數(shù)據(jù)。
要在Dart中執(zhí)行異步操作,可以使用Future類和async和await關鍵字。
1.dart 事件隊列
Dart的事件循環(huán)(event loop)
在Dart中,實際上有兩種隊列:
a.用來處理外部的事件,如果IO、點擊、繪制、計時器(timer)和不同 isolate 之間的消息事件等。。
將任務添加到MicroTask隊列有兩種方法
import 'dart:async';
void myTask(){
print("this is my task");
}
void main() {
# 1. 使用 scheduleMicrotask 方法添加
scheduleMicrotask(myTask);
# 2. 使用Future對象添加
new Future.microtask(myTask);
}
b.微任務隊列(microtask queue),處理來自于Dart內部的任務,適合用來不會特別耗時或緊急的任務。表示一個短時間內就會完成的異步任務。它的優(yōu)先級最高,高于event queue,只要隊列中還有任務,就可以一直霸占著事件循環(huán)。microtask queue添加的任務主要是由 Dart內部產生。
在每一次事件循環(huán)中,Dart總是先去第一個microtask queue中查詢是否有可執(zhí)行的任務,如果沒有,才會處理后續(xù)的event queue的流程。異步任務我們用的最多的還是優(yōu)先級更低的 event queue。Dart為 event queue 的任務建立提供了一層封裝,就是我們在Dart中經常用到的Future。
事件循環(huán)的運行機制:當應用啟動后,它會創(chuàng)建一個isolate,啟動事件循環(huán),按照FIFO的順序,優(yōu)先處理微任務隊列,然后再處理事件隊列,如此反復。
三、多線程
注:以下當我們提到isolate的時候,你可以把它等同于線程,但我們知道它不僅僅是一個線程。
1.Isolate
2.compute
1.Isolate
得益于異步 IO + 事件循環(huán),盡管Dart是單線程,一般的IO密集型App應用通常也能獲得出色的性能表現(xiàn)。但對于一些計算量巨大的場景,比如圖片處理、反序列化、文件壓縮這些計算密集型的操作,只單靠一個線程就不夠用了。
在Dart中,你可以通過Isolate.spawn 來創(chuàng)建一個新的isolate:
void newIsolate(String mainMessage){
sleep(Duration(seconds: 3));
print(mainMessage);
}
void main() {
// 創(chuàng)建一個新的isolate,newIoslate
Isolate.spawn(newIsolate, 'Hello, Im from new isolate!');
sleep(Duration(seconds: 10)); //主線程阻塞等待
}
輸出:
Hello, Im from new isolate!
spawn 有兩個必傳參數(shù),第一個是新isolate入口函數(shù)(entrypoint),第二個是這個入口函數(shù)的參數(shù)值(message)。
如果主isolate想接收子isolate的消息,可以在主isolate創(chuàng)建一個ReceivePort對象,并把對應的receivePort.sendPort作為新isolate入口函數(shù)參數(shù)傳入,然后通過ReceivePort綁定SendPort對象給主isolate發(fā)送消息:
//新isolate入口函數(shù)
void newIsolate(SendPort sendPort){
sendPort.send("hello, Im from new isolate!");
}
void main() async{
ReceivePort receivePort= ReceivePort();
Isolate isolate = await Isolate.spawn(newIsolate, receivePort.sendPort);
receivePort.listen((message){ //監(jiān)聽從新isolate發(fā)送過來的消息
print(message);
// 不再使用時,關閉管道
receivePort.close();
// 關閉isolate線程
isolate?.kill(priority: Isolate.immediate);
});
}
輸出:
hello, Im from new isolate!
上面我們了解了主isolate是如何監(jiān)聽來自子isolate的消息的,如果同時子isolate也想知道主isolate的一些狀態(tài),那該如何處理呢?下面的代碼將提供一種雙向通信的方式:
Future<SendPort> initIsolate() async {
Completer completer = new Completer<SendPort>();
ReceivePort isolateToMainStream = ReceivePort();
//監(jiān)聽來自子線程的消息
isolateToMainStream.listen((data) {
if (data is SendPort) {
SendPort mainToIsolateStream = data;
completer.complete(mainToIsolateStream);
} else {
print('[isolateToMainStream] $data');
}
});
Isolate myIsolateInstance = await Isolate.spawn(newIsolate, isolateToMainStream.sendPort);
//返回來自子isolate的sendPort
return completer.future;
}
void newIsolate(SendPort isolateToMainStream) {
ReceivePort mainToIsolateStream = ReceivePort();
//關鍵實現(xiàn):把SendPort對象傳回給主isolate
isolateToMainStream.send(mainToIsolateStream.sendPort);
//監(jiān)聽來自主isolate的消息
mainToIsolateStream.listen((data) {
print('[mainToIsolateStream] $data');
});
isolateToMainStream.send('This is from new isolate');
}
void main() async{
SendPort mainToIsolate = await initIsolate();
mainToIsolate.send('This is from main isolate');
}
輸出:
[mainToIsolateStream] This is from main isolatemain end
[isolateToMainStream] This is from new isolate
2.compute
你還可以通過一個簡化版的compute函數(shù)啟動一個新的isolate。
比如在反序列化的場景中,直接在主isolate進行序列化:
List<Photo> parsePhotos(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
await client.get('https://jsonplaceholder.typicode.com/photos');
//直接在主isolate轉換
return parsePhotos(response.body);
}
啟動一個新的isolate:
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
await client.get('https://jsonplaceholder.typicode.com/photos');
// 使用compute函數(shù),啟動一個新的isolate
return compute(parsePhotos, response.body);
}
總結一下,當遇到計算密集型的耗時操作,你可以開啟一個新的isolate來并發(fā)執(zhí)行任務。不像我們常規(guī)認識的多線程,不同的isolate之間不能共享內存,但通過ReceivePort和SendPort可以構建不同isolate之間的消息通道,另外從別的isolate傳來的消息也是要經過事件循環(huán)的。
四、Future 說一下 Future?
Future,字面意思「未來」,是用來處理異步的工具。
剛才也說過:
Dart 在單線程中是以消息循環(huán)機制來運行的,其中包含兩個任務隊列,一個是“微任務隊列” microtask queue,另一個叫做“事件隊列” event queue。
Future 默認情況下其實就是往「事件隊列」里插入一個事件,當有空余時間的時候就去執(zhí)行,當執(zhí)行完畢后會回調 Future.then(v) 方法。
而我們也可以通過使用 Future.microtask 方法來向 「微任務隊列」中插入一個任務,這樣就會提高他執(zhí)行的效率。
因為在 Dart 每一個 isolate 當中,執(zhí)行優(yōu)先級為 : Main > MicroTask > EventQueue
五、steam 說一下 Stream?
應用場景:網(wǎng)絡狀態(tài)的監(jiān)控
Stream 和 Feature 一樣,都是用來處理異步的工具。
但是 Stream 和 Feature 不同的地方是 Stream 可以接收多個異步結果,而Feature 只有一個。
Stream 的創(chuàng)建可以使用 Stream.fromFuture,也可以使用 StreamController 來創(chuàng)建和控制。
還有一個注意點是:普通的 Stream 只可以有一個訂閱者,如果想要多訂閱的話,要使用 asBroadcastStream()。
六、說一下 mixin?
首先mixin是一個定義類的關鍵字。直譯出來是混入,混合的意思 Dart為了支持多重繼承,引入了mixin關鍵字,它最大的特殊處在于: mixin定義的類不能有構造方法,這樣可以避免繼承多個類而產生的父類構造方法沖突
mixin extends implement 之間的關系?
繼承(關鍵字 extends)、混入 mixins (關鍵字 with)、接口實現(xiàn)(關鍵字 implements)。這三者可以同時存在,前后順序是extends -> mixins -> implements。
Flutter中的繼承是單繼承,子類重寫超類的方法要用@Override,子類調用超類的方法要用super。
在Flutter中,Mixins是一種在多個類層次結構中復用類代碼的方法。mixins的對象是類,mixins絕不是繼承,也不是接口,而是一種全新的特性,可以mixins多個類,mixins的使用需要滿足一定條件。
(1) 使用mixins的條件是什么?
因為mixins使用的條件,隨著Dart版本一直在變,這里講的是Dart2.1中使用mixins的條件:
mixins類只能繼承自object
mixins類不能有構造函數(shù)
一個類可以mixins多個mixins類
可以mixins多個類,不破壞Flutter的單繼承
(2) mixin 怎么指定異常類型?
on關鍵字可用于指定異常類型。 on只能用于被mixins標記的類,例如mixins X on A,意思是要mixins X的話,得先接口實現(xiàn)或者繼承A。這里A可以是類,也可以是接口,但是在mixins的時候用法有區(qū)別.
七、StatefulWidget 的生命周期
initState():Widget 初始化當前 State,在當前方法中是不能獲取到 Context 的,如想獲取,可以試試 Future.delayed()
didChangeDependencies():在 initState() 后調用,State對象依賴關系發(fā)生變化的時候也會調用。
deactivate():當 State 被暫時從視圖樹中移除時會調用這個方法,頁面切換時也會調用該方法,和Android里的 onPause 差不多。
dispose():Widget 銷毀時調用。
didUpdateWidget:Widget 狀態(tài)發(fā)生變化的時候調用。
八、Flutter 如何與 Android iOS 通信?
Flutter 通過 PlatformChannel 與原生進行交互,其中 PlatformChannel 分為三種:
BasicMessageChannel:用于傳遞字符串和半結構化的信息。
MethodChannel:用于傳遞方法調用。Flutter主動調用Native的方法,并獲取相應的返回值。
EventChannel:用于數(shù)據(jù)流(event streams)的通信。
具體可以查看 閑魚技術:深入理解 Flutter Platform Channel。
九、什么是 Widgets、RenderObjects 和 Elements?
Widget 僅用于存儲渲染所需要的信息。
RenderObject 負責管理布局、繪制等操作。
Element 才是這顆巨大的控件樹上的實體。
具體可以查看[譯] Flutter,什么是 Widgets、RenderObjects 和 Elements?
Widget實際上就是Element的配置數(shù)據(jù),Widget樹實際上是一個配置樹,而真正的UI渲染樹是由Element構成;不過,由于Element是通過Widget生成,所以它們之間有對應關系,所以在大多數(shù)場景,我們可以寬泛地認為Widget樹就是指UI控件樹或UI渲染樹。
一個Widget對象可以對應多個Element對象。這很好理解,根據(jù)同一份配置(Widget),可以創(chuàng)建多個實例(Element)。
十、說一下什么是狀態(tài)管理,為什么需要它?
首先狀態(tài)其實是一個概念上的東西,區(qū)分全局狀態(tài)和局部狀態(tài)。
局部狀態(tài)比如說一個控件中輸入的信息,全局狀態(tài)比如是登陸后從后臺請求回來的 userId。
當全局狀態(tài)越來越多,多個頁面共享一個狀態(tài)時,我們就需要管理它。
常用的狀態(tài)管理有:
ScopedModel
BLoC
Redux / FishRedux
Provider
十一、說一下 BLoC 模式?
具體可以查看: Vadaski - Flutter | 狀態(tài)管理探索篇——BLoC(三)
BLoC是一種利用reactive programming方式構建應用的方法,這是一個由流構成的完全異步的世界。

十一、如何統(tǒng)一管理錯誤頁面?
我們都知道,如果在 Flutter 當中出錯的話,那就是一片紅。
可以使用 ErrorWidget.builder 來自定義一個 Widget 就 ok 了。
十二、Stateless Widget和Stateful Widget區(qū)別
Stateless Widget和Stateful Widget區(qū)別
StatelessWidget用于不需要維護狀態(tài)的場景.,StatefulWidget用于狀態(tài)會發(fā)生變化的場景,它們都繼承自Widget
StatelessWidget,重寫了createElement()方法,StatelessElement 間接繼承自Element類,
@override
StatelessElement createElement() => new StatelessElement(this);
StatefulWidget也是重寫了createElement()方法,不同的是返回的Element 對象并不相同;另StatefulWidget類中添加了一個新的接口createState()。
StatefulElement 間接繼承自Element類,與StatefulWidget相對應(作為其配置數(shù)據(jù))。StatefulElement中可能會多次調用createState()來創(chuàng)建狀態(tài)(State)對象。
createState() 用于創(chuàng)建和Stateful widget相關的狀態(tài),它在Stateful widget的生命周期中可能會被多次調用。例如,當一個Stateful widget同時插入到widget樹的多個位置時,F(xiàn)lutter framework就會調用該方法為每一個位置生成一個獨立的State實例,其實,本質上就是一個StatefulElement對應一個State實例。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => new StatefulElement(this);
@protected
State createState();
}
State生命周期
一個StatefulWidget類會對應一個State類,State表示與其對應的StatefulWidget要維護的狀態(tài),
initState()
界面初始化狀態(tài)時調用
didChangeDependencies()
當state狀態(tài)對象發(fā)生變化時調用(典型的場景是當系統(tǒng)語言Locale或應用主題改變時,F(xiàn)lutter framework會通知widget調用此回調。)
build()
主要是用于構建Widget子樹,調用時機如下:
在調用initState()之后。
在調用didUpdateWidget()之后。
在調用setState()之后。
在調用didChangeDependencies()之后。
在State對象從樹中一個位置移除后(會調用deactivate)又重新插入到樹的其它位置之后。
reassemble()
主要用于調試,熱重載時調用,release環(huán)境下不會調用
didUpdateWidget()
用于更新widget ,Widget.canUpdate返回true則會調用此回調
deactivate()
從widget樹中移除State對象t時調用(位置交換)
dispose()
從widget樹中移除State對象,并不再插入此State對象時調用(一般用于釋放資源)
十三、為什么第一個Flutter應用構建需要這么長時間?
首次構建Flutter應用時, 將花費更長的時間。這是因為Flutter構建了設備專用的APK或IPA文件。因此, Gradle和Xcode用于構建文件, 需要很長時間。
對象鎖和類鎖
dart是值傳遞還是引用傳遞
await for使用
十四、使用mixins的條件是什么?
因為mixins使用的條件,隨著Dart版本一直在變,這里講的是Dart2.1中使用mixins的條件:
mixins類只能繼承自object
mixins類不能有構造函數(shù)
一個類可以mixins多個mixins類
可以mixins多個類,不破壞Flutter的單繼承
十五、Future和Isolate有什么區(qū)別?
future是異步編程,調用本身立即返回,并在稍后的某個時候執(zhí)行完成時再獲得返回結果。在普通代碼中可以使用await 等待一個異步調用結束。
isolate是并發(fā)編程,Dartm有并發(fā)時的共享狀態(tài),所有Dart代碼都在isolate中運行,包括最初的main()。每個isolate都有它自己的堆內存,意味著其中所有內存數(shù)據(jù),包括全局數(shù)據(jù),都僅對該isolate可見,它們之間的通信只能通過傳遞消息的機制完成,消息則通過端口(port)收發(fā)。isolate只是一個概念,具體取決于如何實現(xiàn),比如在Dart VM中一個isolate可能會是一個線程,在Web中可能會是一個Web Worker。
十六、Flutter中的Widget、State、Context 的核心概念?是為了解決什么問題?
Widget: 在Flutter中,幾乎所有東西都是Widget。將一個Widget想象為一個可視化的組件(或與應用可視化方面交互的組件),當你需要構建與布局直接或間接相關的任何內容時,你正在使用Widget。
Widget樹: Widget以樹結構進行組織。包含其他Widget的widget被稱為父Widget(或widget容器)。包含在父widget中的widget被稱為子Widget。
Context: 僅僅是已創(chuàng)建的所有Widget樹結構中的某個Widget的位置引用。簡而言之,將context作為widget樹的一部分,其中context所對應的widget被添加到此樹中。一個context只從屬于一個widget,它和widget一樣是鏈接在一起的,并且會形成一個context樹。
State: 定義了StatefulWidget實例的行為,它包含了用于”交互/干預“Widget信息的行為和布局。應用于State的任何更改都會強制重建Widget。
這些狀態(tài)的引入,主要是為了解決多個部件之間的交互和部件自身狀態(tài)的維護。
十七、什么是Navigator? MaterialApp做了什么?
Navigator是在Flutter中負責管理維護頁面堆棧的導航器。MaterialApp在需要的時候,會自動為我們創(chuàng)建Navigator。Navigator.of(context),會使用context來向上遍歷Element樹,找到MaterialApp提供的_NavigatorState再調用其push/pop方法完成導航操作。
十八、簡述Flutter的線程管理模型
默認情況下,F(xiàn)lutter Engine層會創(chuàng)建一個Isolate,并且Dart代碼默認就運行在這個主Isolate上。必要時可以使用spawnUri和spawn兩種方式來創(chuàng)建新的Isolate,在Flutter中,新創(chuàng)建的Isolate由Flutter進行統(tǒng)一的管理。
事實上,F(xiàn)lutter Engine自己不創(chuàng)建和管理線程,F(xiàn)lutter Engine線程的創(chuàng)建和管理是Embeder負責的,Embeder指的是將引擎移植到平臺的中間層代碼,F(xiàn)lutter Engine層的架構示意圖如下圖所示。

Flutter的架構中,Embeder提供四個Task Runner,分別是Platform Task Runner、UI Task Runner Thread、GPU Task Runner和IO Task Runner,每個Task Runner負責不同的任務,F(xiàn)lutter Engine不在乎Task Runner運行在哪個線程,但是它需要線程在整個生命周期里面保持穩(wěn)定。
十九、請簡單介紹下Flutter框架,以及它的優(yōu)缺點?
Flutter是Google推出的一套開源跨平臺UI框架,可以快速地在Android、iOS和Web平臺上構建高質量的原生用戶界面。同時,F(xiàn)lutter還是Google新研發(fā)的Fuchsia操作系統(tǒng)的默認開發(fā)套件。在全世界,F(xiàn)lutter正在被越來越多的開發(fā)者和組織使用,并且Flutter是完全免費、開源的。Flutter采用現(xiàn)代響應式框架構建,其中心思想是使用組件來構建應用的UI。當組件的狀態(tài)發(fā)生改變時,組件會重構它的描述,F(xiàn)lutter會對比之前的描述,以確定底層渲染樹從當前狀態(tài)轉換到下一個狀態(tài)所需要的最小更改。
優(yōu)點
熱重載(Hot Reload),利用Android Studio直接一個ctrl+s就可以保存并重載,模擬器立馬就可以看見效果,相比原生冗長的編譯過程強很多;
一切皆為Widget的理念,對于Flutter來說,手機應用里的所有東西都是Widget,通過可組合的空間集合、豐富的動畫庫以及分層課擴展的架構實現(xiàn)了富有感染力的靈活界面設計;
借助可移植的GPU加速的渲染引擎以及高性能本地代碼運行時以達到跨平臺設備的高質量用戶體驗。簡單來說就是:最終結果就是利用Flutter構建的應用在運行效率上會和原生應用差不多。
缺點
不支持熱更新;
三方庫有限,需要自己造輪子;
Dart語言編寫,增加了學習難度,并且學習了Dart之后無其他用處,相比JS和Java來說。
二十、 介紹下Flutter的理念架構

由上圖可知,F(xiàn)lutter框架自下而上分為Embedder、Engine和Framework三層。其中,Embedder是操作系統(tǒng)適配層,實現(xiàn)了渲染
Surface設置,線程設置,以及平臺插件等平臺相關特性的適配;Engine層負責圖形繪制、文字排版和提供Dart運行時,Engine層具有獨立虛擬機,正是由于它的存在,F(xiàn)lutter程序才能運行在不同的平臺上,實現(xiàn)跨平臺運行;Framework層則是使用Dart編寫的一套基礎視圖庫,包含了動畫、圖形繪制和手勢識別等功能,是使用頻率最高的一層。
二十一、介紹下FFlutter的FrameWork層和Engine層,以及它們的作用
Flutter的FrameWork層是用Drat編寫的框架(SDK),它實現(xiàn)了一套基礎庫,包含Material(Android風格UI)和Cupertino(iOS風格)的UI界面,下面是通用的Widgets(組件),之后是一些動畫、繪制、渲染、手勢庫等。這個純
Dart實現(xiàn)的 SDK被封裝為了一個叫作 dart:ui的 Dart庫。我們在使用 Flutter寫
App的時候,直接導入這個庫即可使用組件等功能。
Flutter的Engine層是Skia
2D的繪圖引擎庫,其前身是一個向量繪圖軟件,Chrome和 Android均采用 Skia作為繪圖引擎。Skia提供了非常友好的
API,并且在圖形轉換、文字渲染、位圖渲染方面都提供了友好、高效的表現(xiàn)。Skia是跨平臺的,所以可以被嵌入到 Flutter的 iOS
SDK中,而不用去研究 iOS閉源的 Core Graphics / Core Animation。Android自帶了 Skia,所以
Flutter Android SDK要比 iOS SDK小很多。
二十二、 簡述Flutter 的熱重載
Flutter 的熱重載是基于 JIT 編譯模式的代碼增量同步。由于 JIT 屬于動態(tài)編譯,能夠將 Dart 代碼編譯成生成中間代碼,讓 Dart VM 在運行時解釋執(zhí)行,因此可以通過動態(tài)更新中間代碼實現(xiàn)增量同步。
熱重載的流程可以分為
5 步,包括:掃描工程改動、增量編譯、推送更新、代碼合并、Widget 重建。Flutter 在接收到代碼變更后,并不會讓 App
重新啟動執(zhí)行,而只會觸發(fā) Widget 樹的重新繪制,因此可以保持改動前的狀態(tài),大大縮短了從代碼修改到看到修改產生的變化之間所需要的時間。
另一方面,由于涉及到狀態(tài)的保存與恢復,涉及狀態(tài)兼容與狀態(tài)初始化的場景,熱重載是無法支持的,如改動前后 Widget 狀態(tài)無法兼容、全局變量與靜態(tài)屬性的更改、main 方法里的更改、initState 方法里的更改、枚舉和泛型的更改等。
可以發(fā)現(xiàn),熱重載提高了調試 UI 的效率,非常適合寫界面樣式這樣需要反復查看修改效果的場景。但由于其狀態(tài)保存的機制所限,熱重載本身也有一些無法支持的邊界。
二十三、簡述Flutter的繪制流程

Flutter只關心向
GPU提供視圖數(shù)據(jù),GPU的 VSync信號同步到 UI線程,UI線程使用 Dart來構建抽象的視圖結構,這份數(shù)據(jù)結構在
GPU線程進行圖層合成,視圖數(shù)據(jù)提供給 Skia引擎渲染為 GPU數(shù)據(jù),這些數(shù)據(jù)通過 OpenGL或者 Vulkan提供給 GPU。
二十四、dart是值傳遞還是引用傳遞?
首先給個結論,dart是值傳遞。我們每次調用函數(shù),傳遞過去的都是對象的內存地址,而不是這個對象的復制。
我們只要記住一點,參數(shù)是把內存地址傳過去了,如果對這個內存地址上的對象修改,那么其他位置的引用該內存地址的變量值也會修改。千萬要記住dart中一切都是對象。
二十五、flutter特性
Flutter 是 Google 推出并開源的移動應用開發(fā)框架,主打跨平臺、高保真、高性能。開發(fā)者可以通過 Dart 語言開發(fā) App,一套代碼同時運行在 iOS 和 Android平臺。 Flutter 提供了豐富的組件、接口,開發(fā)者可以很快地為 Flutter 添加 Native 擴展。
》高性能
Flutter 高性能主要靠兩點來保證:
第一:Flutter APP 采用 Dart 語言開發(fā)。Dart 在 JIT(即時編譯)模式下,執(zhí)行速度與 JavaScript 基本持平。但是 Dart 支持 AOT,當以 AOT模式運行時,JavaScript 便遠遠追不上了。執(zhí)行速度的提升對高幀率下的視圖數(shù)據(jù)計算很有幫助。
第二:Flutter 使用自己的渲染引擎來繪制 UI ,布局數(shù)據(jù)等由 Dart 語言直接控制,所以在布局過程中不需要像 RN 那樣要在 JavaScript 和 Native 之間通信,這在一些滑動和拖動的場景下具有明顯優(yōu)勢,因為在滑動和拖動過程往往都會引起布局發(fā)生變化,所以 JavaScript 需要和 Native 之間不停的同步布局信息,這和在瀏覽器中JavaScript 頻繁操作 DOM 所帶來的問題是類似的,都會導致比較可觀的性能開銷。
》效率高
Dart 運行時和編譯器支持 Flutter 的兩個關鍵特性的組合:
基于 JIT 的快速開發(fā)周期:Flutter 在開發(fā)階段采用,采用 JIT 模式,這樣就避免了每次改動都要進行編譯,極大的節(jié)省了開發(fā)時間;
基于 AOT 的發(fā)布包: Flutter 在發(fā)布時可以通過 AOT 生成高效的機器碼以保證應用性能。而 JavaScript 則不具有這個能力。
二十六、PlatformView
platform view 就是 AndroidView 和 UIKitView 的總稱,允許將 native view 嵌入到了 flutter widget 體系中,完成 Datr 代碼對 native view 的控制。
https://www.cnblogs.com/ClientInfra/articles/15248565.html(原理)
二十七、flutter從加載到顯示
https://mp.weixin.qq.com/s/ncViI0KGikPUIZ7BlEHGOA
main是的作用及調用時機
flutter為什么既要支持運行時編譯又要支持運行前編譯
dart傳參的基本方式
都了解過哪些跨平臺技術并聊一下其優(yōu)缺點
Flutter生命周期介紹
說一下你了解的一些dart語法規(guī)范
js了解多少
final與const區(qū)別,
with關鍵字的作用
?、??、??=三者的區(qū)別
如何捕捉異常,同步異步
Map如何轉Modal
stateless和stateful的區(qū)別,為什么根Widget要使用stateless,
如何在啟動圖消失之前初始化信息
Provider的使用,
使用GestureDetector碰到的坑
flutter的兩種路由方式
如何使用Controller調用子節(jié)點的方法
動畫及自定義動畫
讓你影響深刻的一些坑及填坑經驗
如何做全局路由
flutter項目如何抓包
聊一聊flutterboost的使用場景
如何將Flutter 模塊嵌入純Native項目,及都需要注意哪些事項
如何維護一個路由棧
說下Widgets、RenderObjects 和 Elements的關系
Flutter 是如何與原生Android、iOS進行通信的?
設計一個日志系統(tǒng),
flutter項目的性能優(yōu)化
Flutter里的各種key
了解過持續(xù)化集成不
設計一個性能監(jiān)控系統(tǒng)
flutter的通信原理
flutter渲染原理
事件循環(huán)
widget的root節(jié)點
mixin extends implement之間的關系(除了extends其他的沒怎么用過。。)
jvm內存模型(感覺這個是面試官可憐我,看我什么都不會才問的=。=)
介紹下inheritwidget
flutter中都有哪幾種線程?
Platform Task Runner
UI Task Runner
GPU Task Runner
IO Task Runner
什么是狀態(tài)管理,了解哪些狀態(tài)管理框架
如何在flutter中使用rootBundle加載圖像?
如何取消Future.delayed函數(shù)調用
Provider.of(context,listen:false)是否等同于context.read()?
如何制作一個ListView.builder從一個特定的索引開始
初始化Dart VM時Flutter應用程序出現(xiàn)錯誤:錯誤的完整快照版本,預期為“ 8343…”發(fā)現(xiàn)為“ 46b2…”
從Firebase Datasnapshot獲取JSON密鑰值
Flutter:如何將變量從StatelessWidget傳遞到StatefulWidget
什么是flutter里的key? 有什么用?
key是Widgets,Elements和SemanticsNodes的標識符。
key有LocalKey 和 GlobalKey兩種。
LocalKey 如果要修改集合中的控件的順序或數(shù)量。GlobalKey允許 Widget 在應用中的任何位置更改父級而不會丟失 State。
在什么場景下使用profile mode?
profile model 是用來評估app性能的,profile model 和release mode是相似的,只有保留了一些需要評估app性能的debug功能。在模擬器上profile model是不可用的。
怎么做到只在debug mode運行代碼?
foundation有一個靜態(tài)的變量kReleaseMode來表示是否是release mode
Dart的一些重要概念?
在Dart中,一切都是對象,所有的對象都是繼承自Object
Dart是強類型語言,但可以用var或 dynamic來聲明一個變量,Dart會自動推斷其數(shù)據(jù)類型,dynamic類似c#
沒有賦初值的變量都會有默認值null
Dart支持頂層方法,如main方法,可以在方法內部創(chuàng)建方法
Dart支持頂層變量,也支持類變量或對象變量
Dart沒有public protected private等關鍵字,如果某個變量以下劃線(_)開頭,代表這個變量在庫中是私有的