如下圖所示,通過(guò)提取編譯后的代碼,「可以看到 playerAnimation 其實(shí)被轉(zhuǎn)變成了 Animation? 的可空對(duì)象」,而當(dāng) playerAnimation 被調(diào)用時(shí),通過(guò) get playerAnimation() 進(jìn)行判斷,如果此時(shí) playerAnimation == null , 直接就拋出 LateError 錯(cuò)誤。
「所以當(dāng)我們?cè)L問(wèn) late 聲明的對(duì)象時(shí),如果對(duì)象還沒(méi)有初始化,就會(huì)返回一個(gè)異常?!?/strong>
[]( )typedef
===================================================================
介紹完 late 接下介紹下 typedef, typedef 在 Dart 2.13 開(kāi)始可以用于**「新的類型別名功能」**,比如:
// Type alias for functions (existing)
typedef ValueChanged
// Type alias for classes (new!)
typedef StringList = List
// Rename classes in a non-breaking way (new!)
@Deprecated("Use NewClassName instead")
typedef OldClassName
那么 typedef 是如何工作的?如下圖所示,可以看到 _getDeviceInfo 方法在編譯后,其實(shí)直接就被替換為 List ,所以**「實(shí)際上 StringList 是不參與到編譯后的代碼運(yùn)行」**,所以也不會(huì)對(duì)代碼的運(yùn)行效率有什么影響。
再舉個(gè)例子,如下圖所示,可以看到通過(guò) SelectItemChanged 聲明的 selectItemChanged,在編譯后其實(shí)直接就是 final field (dynamic) →? void selectItemChanged; 。
接著我們通過(guò) Dart 的 tear-off 來(lái)看另外一個(gè)現(xiàn)象,如下圖所示,可以看到我們從一個(gè)任意對(duì)象中 x中提取了 toString方法,通過(guò)閉包,就可以像調(diào)用常規(guī)實(shí)例一樣調(diào)用 x。
?
如果在一個(gè)對(duì)象上調(diào)用函數(shù)并省略了括號(hào), Dart 稱之為 ”tear-off” :一個(gè)和函數(shù)使用同樣參數(shù)的閉包,當(dāng)調(diào)用閉包的時(shí)候會(huì)執(zhí)行其中的函數(shù),比如:names.forEach(print); 等同于 names.forEach((name){print(name);});
?
那么編譯后的 getToString 方法會(huì)是怎么樣的?
如下圖所示,可以看到 getToString 方法在編譯后成了一個(gè) static 的靜態(tài)方法,并且 ToStringFn 也沒(méi)有實(shí)際參與運(yùn)行,也是被替換成了對(duì)應(yīng)的 ()-> core:String 。
「所以對(duì)于編譯后的代碼,typedef 并不會(huì)對(duì)性能和運(yùn)行結(jié)果產(chǎn)生影響?!?/strong>
[]( )extension
=====================================================================
在 Dart 里,通過(guò) extension 可以很便捷地為對(duì)象進(jìn)行拓展,「那 extension 關(guān)鍵字是如何在原對(duì)象基礎(chǔ)上實(shí)現(xiàn)拓展呢?」
如下圖所示,我們聲明了一個(gè) Cat 的枚舉,并且對(duì) Cat 進(jìn)行了拓展,從而為枚舉的每個(gè)值賦值,并且加了 talk 方法。
如下圖所示,「編譯后 Cat 里的枚舉值對(duì)應(yīng)變成了一個(gè) static final 的固定地址」,并且 CatExtension 里的 talk 和 value 也被指向了新的位置。
找到對(duì)應(yīng)的實(shí)現(xiàn)處發(fā)現(xiàn),「CatExtension 里的 name 和 talk 都變了所在文件下的 static method」 ,并且 talk 方法是先定義了 method 實(shí)現(xiàn),之后再通過(guò) tearoff 的 get 實(shí)現(xiàn)去調(diào)用,「基本上所有在 extension 里定義的方法都會(huì)有對(duì)應(yīng)的 method 和 tearoff?!?/strong>
如下圖所示,在 Cat 的使用處,編譯后可以看到 cat.talk() 其實(shí)就是執(zhí)行了 main::CatExtension|talk 。
[]( )async / await
=========================================================================
最后聊聊 async / await ,我們都知道這是 Dart 里 Future 的語(yǔ)法糖,那這個(gè)語(yǔ)法糖在編譯后是如何運(yùn)行的呢?
可以看到,loadmore 方法在編譯后被添加了很多的代碼,其中定義了一個(gè) _Future async_future 并在最后返回,同時(shí)我們需要執(zhí)行的代碼被包裝到 async_op 里去執(zhí)行,而這里有一個(gè)很關(guān)鍵的地方就是,「async_op 對(duì)執(zhí)行的內(nèi)容進(jìn)行了 try catch 的操作,并通過(guò) _completeOnAsyncError 返回」。
「這也是為什么我們?cè)谕獠繉?duì)一個(gè) Future 進(jìn)行 try catch 不能捕獲異常的原因」,所以如下圖所示,對(duì)于 Future 需要通過(guò) .onError((error, stackTrace) => null) 的方式來(lái)對(duì)異常進(jìn)行捕獲處理。
明白了這些關(guān)鍵字背后的實(shí)現(xiàn)后,相信可以更好地幫助你在 Flutter 的日常開(kāi)發(fā)中更優(yōu)雅地組織你的代碼,從而避免很多不必要的問(wèn)題。
「當(dāng)然,如果用不上,拿去面試“裝X”其實(shí)也挺不錯(cuò)的不是么?」
結(jié)語(yǔ)
- 現(xiàn)在隨著短視頻,抖音,快手的流行NDK模塊開(kāi)發(fā)也顯得越發(fā)重要,需要這塊人才的企業(yè)也越來(lái)越多,隨之學(xué)習(xí)這塊的人也變多了,音視頻的開(kāi)發(fā),往往是比較難的,而這個(gè)比較難的技術(shù)就是NDK里面的技術(shù)。
- 音視頻/高清大圖片/人工智能/直播/抖音等等這年與用戶最緊密,與我們生活最相關(guān)的技術(shù)一直都在尋找最終的技術(shù)落地平臺(tái),以前是windows系統(tǒng),而現(xiàn)在則是移動(dòng)系統(tǒng)了,移動(dòng)系統(tǒng)中又是以Android占比絕大部分為前提,所以AndroidNDK技術(shù)已經(jīng)是我們必備技能了。
- 要學(xué)習(xí)好NDK,其中的關(guān)于C/C++,jni,Linux基礎(chǔ)都是需要學(xué)習(xí)的,除此之外,音視頻的編解碼技術(shù),流媒體協(xié)議,ffmpeg這些都是音視頻開(kāi)發(fā)必備技能,而且
- OpenCV/OpenGl/這些又是圖像處理必備知識(shí),下面這些我都是當(dāng)年自己搜集的資料和做的一些圖,因?yàn)楫?dāng)年我就感覺(jué)視頻這塊會(huì)是一個(gè)大的趨勢(shì)。所以提前做了一些準(zhǔn)備。現(xiàn)在拿出來(lái)分享給大家。
本文已被[CODING開(kāi)源項(xiàng)目:《Android學(xué)習(xí)筆記總結(jié)+移動(dòng)架構(gòu)視頻+大廠面試真題+項(xiàng)目實(shí)戰(zhàn)源碼》]( )收錄