摘要:中的的線程是以事件循環(huán)和消息隊(duì)列的形式存在,包含兩個(gè)任務(wù)隊(duì)列,一個(gè)是內(nèi)部隊(duì)列,一個(gè)是外部隊(duì)列,而的優(yōu)先級(jí)又高于。同時(shí)還有處理按住時(shí)的事件額外處理,同時(shí)手勢(shì)處理一般在的子類進(jìn)行。
谷歌大會(huì)之后,有不少人咨詢了我 Flutter 相關(guān)的問(wèn)題,其中有不少是和面試相關(guān)的,如今一些招聘上也開始羅列 Flutter 相關(guān)要求,最后想了想還是寫一期總結(jié)吧,也算是 Flutter 的階段復(fù)習(xí)。
??系統(tǒng)完整的學(xué)習(xí)是必須需要的,這里只能幫你總結(jié)一些知識(shí)點(diǎn),更多的還請(qǐng)查閱 Dart/Flutter 官網(wǎng)。
本篇主要是知識(shí)點(diǎn)總結(jié),如有疑問(wèn)可點(diǎn)擊各文章鏈接了解詳情,或者查閱我 掘金專欄。
Dart 部分
其實(shí)學(xué)習(xí)過(guò) JavaScript 或者 Java/Kotlin 的人,在學(xué)習(xí) Dart 上幾乎是沒(méi)什么難度的,Dart 綜合了動(dòng)態(tài)語(yǔ)言和靜態(tài)語(yǔ)言的特性, 這里主要提供一些不一樣,或者有意思的概念。
1、Dart 屬于是強(qiáng)類型語(yǔ)言 ,但可以用 var 來(lái)聲明變量,Dart 會(huì)自推導(dǎo)出數(shù)據(jù)類型,var 實(shí)際上是編譯期的“語(yǔ)法糖”。dynamic 表示動(dòng)態(tài)類型, 被編譯后,實(shí)際是一個(gè) object 類型,在編譯期間不進(jìn)行任何的類型檢查,而是在運(yùn)行期進(jìn)行類型檢查。
2、Dart 中 if 等語(yǔ)句只支持 bool 類型,switch 支持 String 類型。
3、Dart 中數(shù)組和 List 是一樣的。
4、Dart 中,Runes 代表符號(hào)文字 , 是 UTF-32 編碼的字符串, 用于如 Runes input = new Runes("u{1f596} u{1f44d}");
5、Dart 支持閉包。
6、Dart 中 number 類型分為 int 和 double ,沒(méi)有 float 類型。
7、Dart 中 級(jí)聯(lián)操作符 可以方便配置邏輯,如下代碼:
event ..id = 1 ..type = "" ..actor = "";
8、賦值操作符
比較有意思的賦值操作符有:
AA ");
9、可選方法參數(shù)
Dart 方法可以設(shè)置 參數(shù)默認(rèn)值 和 指定名稱 。
比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法,這里 branch 不設(shè)置的話,默認(rèn)是 “master” 。參數(shù)類型 可以指定或者不指定。調(diào)用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev"); 。
10、作用域
Dart 沒(méi)有關(guān)鍵詞 public 、private 等修飾符,_ 下橫向直接代表 private ,但是有 @protected 注解 。
11、構(gòu)造方法
Dart 中的多構(gòu)造方法,可以通過(guò)命名方法實(shí)現(xiàn)。
默認(rèn)構(gòu)造方法只能有一個(gè),而通過(guò) Model.empty() 方法可以創(chuàng)建一個(gè)空參數(shù)的類,其實(shí)方法名稱隨你喜歡,而變量初始化值時(shí),只需要通過(guò) this.name 在構(gòu)造方法中指定即可:
class ModelA { String name; String tag; //默認(rèn)構(gòu)造方法,賦值給name和tag ModelA(this.name, this.tag); //返回一個(gè)空的ModelA ModelA.empty(); //返回一個(gè)設(shè)置了name的ModelA ModelA.forName(this.name); }
12、getter setter 重寫
Dart 中所有的基礎(chǔ)類型、類等都繼承 Object ,默認(rèn)值是 NULL, 自帶 getter 和 setter ,而如果是 final 或者 const 的話,那么它只有一個(gè) getter 方法,Object 都支持 getter、setter 重寫:
@override Size get preferredSize { return Size.fromHeight(kTabHeight + indicatorWeight); }
13、Assert(斷言)
assert 只在檢查模式有效,在開發(fā)過(guò)程中,assert(unicorn == null); 只有條件為真才正常,否則直接拋出異常,一般用在開發(fā)過(guò)程中,某些地方不應(yīng)該出現(xiàn)什么狀態(tài)的判斷。
14、重寫運(yùn)算符,如下所示重載 operator 后對(duì)類進(jìn)行 +/- 操作。
class Vector { final int x, y; Vector(this.x, this.y); Vector operator +(Vector v) => Vector(x + v.x, y + v.y); Vector operator -(Vector v) => Vector(x - v.x, y - v.y); ··· } void main() { final v = Vector(2, 3); final w = Vector(2, 2); assert(v + w == Vector(4, 5)); assert(v - w == Vector(0, 1)); }
支持重載的操作符 :
類、接口、繼承
Dart 中沒(méi)有接口,類都可以作為接口,把某個(gè)類當(dāng)做接口實(shí)現(xiàn)時(shí),只需要使用 implements ,然后復(fù)寫父類方法即可。
Dart 中支持 mixins ,按照出現(xiàn)順序應(yīng)該為extends 、 mixins 、implements 。
Zone
Dart 中可通過(guò) Zone 表示指定代碼執(zhí)行的環(huán)境,類似一個(gè)沙盒概念,在 Flutter 中 C++ 運(yùn)行 Dart 也是在 _runMainZoned 內(nèi)執(zhí)行 runZoned 方法啟動(dòng),而我們也可以通過(guò) Zone ,在運(yùn)行環(huán)境內(nèi)捕獲全局異常等信息:
runZoned(() { runApp(FlutterReduxApp()); }, onError: (Object obj, StackTrace stack) { print(obj); print(stack); });
同時(shí)你可以給 runZoned 注冊(cè)方法,在需要時(shí)執(zhí)行回調(diào),如下代碼所示,這樣的在一個(gè) Zone 內(nèi)任何地方,只要能獲取 onData 這個(gè) ZoneUnaryCallback,就都可以調(diào)用到 handleData
///最終需要處理的地方 handleData(result) { print("VVVVVVVVVVVVVVVVVVVVVVVVVVV"); print(result); } ///返回得到一個(gè) ZoneUnaryCallback var onData = Zone.current.registerUnaryCallback
(handleData); ///執(zhí)行 ZoneUnaryCallback 返回?cái)?shù)據(jù) Zone.current.runUnary(onData, 2); 異步邏輯可以通過(guò) scheduleMicrotask 可以插入異步執(zhí)行方法:
Zone.current.scheduleMicrotask((){ //todo something });
更多可參看 :《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十一、全面深入理解Stream)》
Future
Future 簡(jiǎn)單了說(shuō)就是對(duì) Zone 的封裝使用。
比如 Future.microtask 中主要是執(zhí)行了 Zone 的 scheduleMicrotask ,而 result._complete 最后調(diào)用的是 _zone.runUnary 等等。
factory Future.microtask(FutureOr
computation()) { _Future result = new _Future (); scheduleMicrotask(() { try { result._complete(computation()); } catch (e, s) { _completeWithErrorCallback(result, e, s); } }); return result; } Dart 中可通過(guò) async/await 或者 Future 定義異步操作,而事實(shí)上 async/await 也只是語(yǔ)法糖,最終還是通過(guò)編譯器轉(zhuǎn)為 Future。
有興趣看這里 :
generators
code_generator.dart
Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十一、全面深入理解Stream)
Stream
Stream 也是有對(duì)Zone 的另外一種封裝使用。
Dart 中另外一種異步操作, async* / yield 或者 Stream 可定義 Stream 異步, async* / yield 也只是語(yǔ)法糖,最終還是通過(guò)編譯器轉(zhuǎn)為 Stream。 Stream 還支持同步操作。
1)、Stream 中主要有 Stream 、 StreamController 、StreamSink 和 StreamSubscription 四個(gè)關(guān)鍵對(duì)象,大致可以總結(jié)為:
StreamController :如類名描述,用于整個(gè) Stream 過(guò)程的控制,提供各類接口用于創(chuàng)建各種事件流。
StreamSink :一般作為事件的入口,提供如 add , addStream 等。
Stream :事件源本身,一般可用于監(jiān)聽事件或者對(duì)事件進(jìn)行轉(zhuǎn)換,如 listen 、where 。
StreamSubscription :事件訂閱后的對(duì)象,表面上用于管理訂閱過(guò)等各類操作,如 cacenl 、pause ,同時(shí)在內(nèi)部也是事件的中轉(zhuǎn)關(guān)鍵。
2)、一般通過(guò) StreamController 創(chuàng)建 Stream;通過(guò) StreamSink 添加事件;通過(guò) Stream 監(jiān)聽事件;通過(guò) StreamSubscription 管理訂閱。
3)、Stream 中支持各種變化,比如map 、expand 、where 、take 等操作,同時(shí)支持轉(zhuǎn)換為 Future 。
更多可參看 :《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十一、全面深入理解Stream)》
Flutter 部分
Flutter 和 React Native 不同主要在于 Flutter UI是直接通過(guò) skia 渲染的 ,而 React Native 是將 js 中的控件轉(zhuǎn)化為原生控件,通過(guò)原生去渲染的 ,相關(guān)更多可查看:《移動(dòng)端跨平臺(tái)開發(fā)的深度解析》。
Flutter 中存在 Widget 、 Element 、RenderObject 、Layer 四棵樹,其中 Widget 與 Element 是多對(duì)一的關(guān)系 ,
Element 中持有Widget 和 RenderObject , 而 Element 與 RenderObject 是一一對(duì)應(yīng)的關(guān)系 ,
當(dāng) RenderObject 的 isRepaintBoundary 為 true 時(shí),那么個(gè)區(qū)域形成一個(gè) Layer,所以不是每個(gè) RenderObject 都具有 Layer 的,因?yàn)檫@受 isRepaintBoundary 的影響。
更多相關(guān)可查閱 《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(九、 深入繪制原理)》
Flutter 中 Widget 不可變,每次保持在一幀,如果發(fā)生改變是通過(guò) State 實(shí)現(xiàn)跨幀狀態(tài)保存,而真實(shí)完成布局和繪制數(shù)組的是 RenderObject , Element 充當(dāng)兩者的橋梁, State 就是保存在 Element 中。
Flutter 中的 BuildContext 只是接口,而 Element 實(shí)現(xiàn)了它。
Flutter 中 setState 其實(shí)是調(diào)用了 markNeedsBuild ,該方法內(nèi)部標(biāo)記此Element 為 Dirty ,然后在下一幀 WidgetsBinding.drawFrame 才會(huì)被繪制,這可以看出 setState 并不是立即生效的。
Flutter 中 RenderObject 在 attch/layout 之后會(huì)通過(guò) markNeedsPaint(); 使得頁(yè)面重繪,流程大概如下:
通過(guò)isRepaintBoundary 往上確定了更新區(qū)域,通過(guò) requestVisualUpdate 方法觸發(fā)更新往下繪制。
正常情況 RenderObject 的布局相關(guān)方法調(diào)用順序是 : layout -> performResize -> performLayout -> markNeedsPaint , 但是用戶一般不會(huì)直接調(diào)用 layout,而是通過(guò) markNeedsLayout ,具體流程如下:
Flutter 中一般 json 數(shù)據(jù)從 String 轉(zhuǎn)為 Object 的過(guò)程中都需要先經(jīng)過(guò) Map 類型。
Flutter 中 InheritedWidget 一般用于狀態(tài)共享,如Theme 、Localizations 、 MediaQuery 等,都是通過(guò)它實(shí)現(xiàn)共享狀態(tài),這樣我們可以通過(guò) context 去獲取共享的狀態(tài),比如 ThemeData theme = Theme.of(context);
在 Element 的 inheritFromWidgetOfExactType 方法實(shí)現(xiàn)里,有一個(gè) Map
_inheritedWidgets 的對(duì)象。_inheritedWidgets 一般情況下是空的,只有當(dāng)父控件是 InheritedWidget 或者本身是 InheritedWidgets 時(shí)才會(huì)有被初始化,而當(dāng)父控件是 InheritedWidget 時(shí),這個(gè) Map 會(huì)被一級(jí)一級(jí)往下傳遞與合并 。
所以當(dāng)我們通過(guò) context 調(diào)用 inheritFromWidgetOfExactType 時(shí),就可以往上查找到父控件的 Widget 。
Flutter 中默認(rèn)主要通過(guò) runtimeType 和 key 判斷更新:
static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; } }
Flutter 中的生命周期
initState() 表示當(dāng)前 State 將和一個(gè) BuildContext 產(chǎn)生關(guān)聯(lián),但是此時(shí)BuildContext 沒(méi)有完全裝載完成,如果你需要在該方法中獲取 BuildContext ,可以 new Future.delayed(const Duration(seconds: 0, (){//context}); 一下。
didChangeDependencies() 在 initState() 之后調(diào)用,當(dāng) State 對(duì)象的依賴關(guān)系發(fā)生變化時(shí),該方法被調(diào)用,初始化時(shí)也會(huì)調(diào)用。
deactivate() 當(dāng) State 被暫時(shí)從視圖樹中移除時(shí),會(huì)調(diào)用這個(gè)方法,同時(shí)頁(yè)面切換時(shí),也會(huì)調(diào)用。
dispose() Widget 銷毀了,在調(diào)用這個(gè)方法之前,總會(huì)先調(diào)用 deactivate()。
didUpdateWidge 當(dāng) widget 狀態(tài)發(fā)生變化時(shí),會(huì)調(diào)用。
通過(guò) StreamBuilder 和 FutureBuilder 我們可以快速使用 Stream 和 Future 快速構(gòu)建我們的異步控件: 《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十一、全面深入理解Stream)》
Flutter 中 runApp 啟動(dòng)入口其實(shí)是一個(gè) WidgetsFlutterBinding ,它主要是通過(guò) BindingBase 的子類 GestureBinding 、ServicesBinding 、 SchedulerBinding 、PaintingBinding 、SemanticsBinding 、 RendererBinding 、WidgetsBinding 等,通過(guò) mixins 的組合而成的。
Flutter 中的 Dart 的線程是以事件循環(huán)和消息隊(duì)列的形式存在,包含兩個(gè)任務(wù)隊(duì)列,一個(gè)是 microtask 內(nèi)部隊(duì)列,一個(gè)是 event 外部隊(duì)列,而 microtask 的優(yōu)先級(jí)又高于 event 。
因?yàn)?microtask 的優(yōu)先級(jí)又高于 event, 同時(shí)會(huì)阻塞event 隊(duì)列,所以如果 microtask 太多就可能會(huì)對(duì)觸摸、繪制等外部事件造成阻塞卡頓哦。
Flutter 中存在四大線程,分別為 UI Runner、GPU Runner、IO Runner, Platform Runner (原生主線程) ,同時(shí)在 Flutter 中可以通過(guò) isolate 或者 compute 執(zhí)行真正的跨線程異步操作。
PlatformView
Flutter 中通過(guò) PlatformView 可以嵌套原生 View 到 Flutter UI 中,這里面其實(shí)是使用了 Presentation + VirtualDisplay + Surface 等實(shí)現(xiàn)的,大致原理就是:
使用了類似副屏顯示的技術(shù),VirtualDisplay 類代表一個(gè)虛擬顯示器,調(diào)用 DisplayManager 的 createVirtualDisplay() 方法,將虛擬顯示器的內(nèi)容渲染在一個(gè) Surface 控件上,然后將 Surface 的 id 通知給 Dart,讓 engine 繪制時(shí),在內(nèi)存中找到對(duì)應(yīng)的 Surface 畫面內(nèi)存數(shù)據(jù),然后繪制出來(lái)。em... 實(shí)時(shí)控件截圖渲染顯示技術(shù)。
Flutter 的 Debug 下是 JIT 模式,release下是AOT模式。
Flutter 中可以通過(guò) mixins AutomaticKeepAliveClientMixin ,然后重寫 wantKeepAlive 保持住頁(yè)面,記得在被保持住的頁(yè)面 build 中調(diào)用 super.build 。(因?yàn)?mixins 特性)。
Flutter 手勢(shì)事件主要是通過(guò)競(jìng)技判斷的:
主要有 hitTest 把所有需要處理的控件對(duì)應(yīng)的 RenderObject , 從 child 到 parent 全部組合成列表,從最里面一直添加到最外層。
然后從隊(duì)列頭的 child 開始 for 循環(huán)執(zhí)行 handleEvent 方法,執(zhí)行 handleEvent 的過(guò)程不會(huì)被攔截打斷。
一般情況下 Down 事件不會(huì)決出勝利者,大部分時(shí)候是在 MOVE 或者 UP 的時(shí)候才會(huì)決出勝利者。
競(jìng)技場(chǎng)關(guān)閉時(shí)只有一個(gè)的就直接勝出響應(yīng),沒(méi)有勝利者就拿排在隊(duì)列第一個(gè)強(qiáng)制勝利響應(yīng)。
同時(shí)還有 didExceedDeadline 處理按住時(shí)的 Down 事件額外處理,同時(shí)手勢(shì)處理一般在 GestureRecognizer 的子類進(jìn)行。
更多詳細(xì)請(qǐng)查看:《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十三、全面深入觸摸和滑動(dòng)原理)》
Flutter 中 ListView 滑動(dòng)其實(shí)都是通過(guò)改變 ViewPort 中的 child 布局來(lái)實(shí)現(xiàn)顯示的。
常用狀態(tài)管理的:目前有 scope_model 、flutter_redux 、fish_redux 、bloc + Stream 等幾種模式,具體可見 : 《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十二、全面深入理解狀態(tài)管理設(shè)計(jì))》
Platform Channel
Flutter 中可以通過(guò) Platform Channel 讓 Dart 代碼和原生代碼通信的:
BasicMessageChannel :用于傳遞字符串和半結(jié)構(gòu)化的信息。
MethodChannel :用于傳遞方法調(diào)用(method invocation)。
EventChanne l: 用于數(shù)據(jù)流(event streams)的通信。
同時(shí) Platform Channel 并非是線程安全的 ,更多詳細(xì)可查閱閑魚技術(shù)的 《深入理解Flutter Platform Channel》
其中基礎(chǔ)數(shù)據(jù)類型映射如下:
Android 啟動(dòng)頁(yè)
Android 中 Flutter 默認(rèn)啟動(dòng)時(shí)會(huì)在 FlutterActivityDelegate.java 中讀取 AndroidManifset.xml 內(nèi) meta-data 標(biāo)簽,其中 io.flutter.app.android.SplashScreenUntilFirstFrame 標(biāo)志位如果為 ture ,就會(huì)啟動(dòng) Splash 畫面效果(類似IOS的啟動(dòng)頁(yè)面)。
啟動(dòng)時(shí)原生代碼會(huì)讀取 android.R.attr.windowBackground 得到指定的 Drawable , 用于顯示啟動(dòng)閃屏效果,之后并且通過(guò) flutterView.addFirstFrameListener,在onFirstFrame 中移除閃屏。
好了,暫時(shí)都這里了,有問(wèn)題修改會(huì)或則補(bǔ)充的,后面再加上。
資源推薦
Github : github.com/CarGuo
本文Demo :github.com/CarGuo/stat…
本文代碼 :github.com/CarGuo/GSYG…
完整開源項(xiàng)目推薦:
GSYGithubApp Flutter
GSYGithubApp React Native
GSYGithubAppWeex
文章
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(一、Dart語(yǔ)言和Flutter基礎(chǔ))》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(二、 快速開發(fā)實(shí)戰(zhàn)篇)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(三、 打包與填坑篇)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(四、Redux、主題、國(guó)際化)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(五、 深入探索)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(六、 深入Widget原理)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(七、 深入布局原理)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(八、 實(shí)用技巧與填坑)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(九、 深入繪制原理)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十、 深入圖片加載流程)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十一、全面深入理解Stream)》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十二、全面深入理解狀態(tài)管理設(shè)計(jì))》
《Flutter完整開發(fā)實(shí)戰(zhàn)詳解(十三、全面深入觸摸和滑動(dòng)原理)》
《跨平臺(tái)項(xiàng)目開源項(xiàng)目推薦》
《移動(dòng)端跨平臺(tái)開發(fā)的深度解析》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/6701.html
摘要:獲取的對(duì)象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對(duì)象即使沒(méi)有代碼,也會(huì)把默認(rèn)的祖宗八代都顯示出來(lái)而只能獲取元素屬性中的樣式。因此對(duì)于一個(gè)光禿禿的元素,方法返回對(duì)象中屬性值如果有就是據(jù)我測(cè)試不同環(huán)境結(jié)果可能有差異而就是。 花了很長(zhǎng)時(shí)間整理的前端面試資源,喜歡請(qǐng)大家不要吝嗇star~ 別只收藏,點(diǎn)個(gè)贊,點(diǎn)個(gè)star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項(xiàng)目地址 https:...
摘要:創(chuàng)建一個(gè)創(chuàng)建遵循準(zhǔn)則的應(yīng)用程序時(shí),請(qǐng)為您的應(yīng)用程序提供一致的外觀結(jié)構(gòu)。例如,如果用戶不小心刪除了一條消息,則他們可以在中使用可選的動(dòng)作來(lái)恢復(fù)該消息。來(lái)自第三方庫(kù)的依賴,是一個(gè)來(lái)自第三方庫(kù)的給用戶彈出提示的實(shí)現(xiàn),它覆蓋了安卓,,及等平臺(tái)。 來(lái)自Material Design的官方Toast,Snackbars在執(zhí)...
摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
閱讀 1238·2021-11-23 09:51
閱讀 2015·2021-10-08 10:05
閱讀 2372·2019-08-30 15:56
閱讀 1926·2019-08-30 15:55
閱讀 2663·2019-08-30 15:55
閱讀 2512·2019-08-30 13:53
閱讀 3525·2019-08-30 12:52
閱讀 1281·2019-08-29 10:57