請列舉至少5個Dart語法糖,并說明其用法和作用
- 操作符與運算符
?.:條件訪問成員,用作條件判空
??:空感知運算符,用于條件判空
??=:空感知賦值運算符,判斷對象是否為空決定是否要給對象賦值
..:級聯(lián)運算符
?..:空感知級聯(lián)運算符
...:擴展操作符
...?:空感知擴展操作符 - 循環(huán)
for-in - 箭頭函數(shù)
=>:語法糖補全了return,同時因為是單行函數(shù),所以不加{} -
await for:用于處理流(Stream)
// 操作符:?.
void main() {
String? name;
var len = name?.length;
print(len); // len is null
}
void main() {
String? name = 'flutter';
var len = name?.length;
print(len); // len is 7
}
// 運算符:??
void main() {
String? name;
var result = name ?? 'Dart';
print(result); // result is Dart
}
void main() {
String? name = 'flutter';
var result = name ?? 'Dart';
print(result); // result is flutter
}
// 運算符:??=
void main() {
String? name;
name ??= 'Dart';
print(name); // name is Dart
}
void main() {
String? name = 'flutter';
name ??= 'Dart';
print(name); // len is flutter
}
請說明一下兩種變量聲明的區(qū)別
(1)late String name;
(2)String name;
- 延遲初始化:late 變量允許在首次訪問時才初始化,而非 late 變量需在聲明或構(gòu)造函數(shù)中立即初始化。
- 編譯時檢查與運行時檢查:late 變量僅在運行時檢查是否已初始化,非 late 變量在編譯時進(jìn)行空安全檢查。
- 默認(rèn)值:late 變量無默認(rèn)值,非 late 變量(在 null 安全環(huán)境下)通常要求在聲明時提供非 null 初始值。
const 和 final 的區(qū)別
- const關(guān)鍵字
- 聲明編譯時常量: 這意味著變量的值在編譯時就已經(jīng)確定,并且在程序運行期間不可更改
- 變量聲明的左側(cè): 此時它要求變量在聲明時就必須賦值,并且賦值必須是編譯時常量。例如,數(shù)值、字符串、其他的const變量或者某些表達(dá)式
- 變量聲明的右側(cè): 此時它修飾的是值,表示該值在編譯時就已經(jīng)確定,并且整個對象是不可變的
- 修飾的集合或?qū)ο? 要求集合的元素必須是遞歸的編譯時常數(shù)。
- 修飾的類的構(gòu)造函數(shù): 要求該類的所有成員都必須是final的
- final關(guān)鍵字
- 聲明不可變的變量: 并不要求變量的值在編譯時就已知
- 賦值時機: 可以在聲明時賦值,也可以在構(gòu)造函數(shù)中賦值
- 初始化: 第一次使用時初始化,如果是在聲明時賦值,那么賦值可以是任意的,不一定是編譯時常量
- 修飾的對象: 內(nèi)部的可變成員仍然可以被修改,除非這些成員也被聲明為final
- 總結(jié):
const比final更嚴(yán)格
要求變量的值在編譯時就已經(jīng)確定,并且在運行時不可變
而final只要求變量在初始化后不可變,但初始化時的值不必在編譯時已知
請依次寫出Widget的生命周期函數(shù)并說明其使用場景

- createState:創(chuàng)建 State 的方法。
- initState:初始化變量,接口請求操作。
- didChangeDependencies ,當(dāng)State對象的依賴發(fā)生變化時會被調(diào)用。
- build ,主要是返回需要渲染的 Widget
- reassemble:在 debug 模式下,每次熱重載都會調(diào)用該函數(shù)。
- didUpdateWidget :在widget重新構(gòu)建時調(diào)用。
- deactivate:在組件被移除節(jié)點后會被調(diào)用。
- dispose:永久移除組件,并釋放組件資源。
ListView和ListView.builder有什么區(qū)別?
- ListView在
初始化時就把所有的children都創(chuàng)建出來 - ListView.builder并不是初始化時把所有的children都創(chuàng)建出來,而是等用戶
滾動到了要創(chuàng)建的位置才會創(chuàng)建出來。(這個構(gòu)造函數(shù)適用于擁有大量(或者無限)子元素的列表視圖,因為它只會為那些實際可見的子元素調(diào)用構(gòu)建器。這樣做可以提高性能,避免不必要的構(gòu)建操作)
InheritedWidget是什么?有什么作用?
InheritedWidget是一種無界面的組件,它提供了自頂向下為子組件共享數(shù)據(jù)的功能。
StreamBuilder和FutureBuilder有什么區(qū)別?各自使用場景是什么?
都是用于根據(jù)異步操作的狀態(tài)動態(tài)構(gòu)建UI的Widget。
- 數(shù)據(jù)源的區(qū)別
StreamBuilder用于處理連續(xù)的異步數(shù)據(jù)流,可以有多個數(shù)據(jù)事件。
FutureBuilder用于處理一次性的異步操作,只有一個結(jié)果。 - 構(gòu)建次數(shù)的區(qū)別
StreamBuilder可能多次調(diào)用其build函數(shù),每當(dāng)新的數(shù)據(jù)事件到達(dá)時。
FutureBuilder只調(diào)用一次其build函數(shù),當(dāng)Future完成時。
Provider與其他狀態(tài)管理解決方案有什么不同?
https://blog.51cto.com/u_16175630/7445520
設(shè)計理念與簡潔性
Provider設(shè)計目標(biāo)是
簡化狀態(tài)管理,通過繼承自InheritedWidget的ChangeNotifierProvider、ValueListenableProvider等類,將狀態(tài)以樹狀結(jié)構(gòu)向下傳遞給子組件。強調(diào)簡單易用。Bloc基于響應(yīng)式編程模式,強調(diào)將
業(yè)務(wù)邏輯(BLoC)與 UI 完全解耦。通過事件流(Event)驅(qū)動狀態(tài)變更(State),并利用 Stream 和 BlocProvider 實現(xiàn)狀態(tài)的分發(fā)。雖然結(jié)構(gòu)相對復(fù)雜,但非常適合大型項目和復(fù)雜的業(yè)務(wù)邏輯,因為它鼓勵模塊化和邏輯復(fù)用。Redux:遵循嚴(yán)格的
單向數(shù)據(jù)流和不可變狀態(tài)原則。它包括 Actions、Reducers 和 Store,形成一個中心化的狀態(tài)管理機制。Redux 提供清晰的調(diào)試工具和高度可預(yù)測的行為,適用于大型團隊協(xié)作和有嚴(yán)格狀態(tài)管理需求的應(yīng)用。ScopedModel:較早的 Flutter 狀態(tài)管理庫,同樣基于
InheritedWidget。它通過定義 Model 類來封裝狀態(tài),并通過 ScopedModel 和 ScopedModelDescendant Widget 分發(fā)和訪問狀態(tài)。相比于 Provider,ScopedModel 的功能較為基礎(chǔ),且對不同類型狀態(tài)的處理不夠靈活。
狀態(tài)更新方式
Provider:依賴于
ChangeNotifier類,狀態(tài)對象通過調(diào)用notifyListeners()方法觸發(fā)狀態(tài)更新通知。也可以使用ValueNotifier、Stream等其他可觀察對象作為狀態(tài)源。Bloc:基于
Stream,狀態(tài)更新通過處理事件流并在其中產(chǎn)生新的狀態(tài)來實現(xiàn)。開發(fā)者編寫事件處理器(event handler),將事件轉(zhuǎn)換為新的狀態(tài)。Redux:狀態(tài)更新通過
Reducer函數(shù)完成。當(dāng) Actions 發(fā)出后,Store 調(diào)用相應(yīng)的 Reducer 函數(shù)處理這些動作,并返回一個新的狀態(tài)對象。新舊狀態(tài)的差異會觸發(fā) UI 更新。ScopedModel:狀態(tài)更新
直接修改 Model 對象的屬性,然后調(diào)用notifyListeners()方法通知依賴組件。
在Flutter中如何優(yōu)化性能?
- 盡量減少消耗資源的操作 (異步)
- 控制 build() 方法的耗時
- 謹(jǐn)慎使用 saveLayer()
- 盡量減少使用不透明度和裁剪
- 使用ListView.builder()
- 盡量減少由內(nèi)部操作引起的布局傳遞
- 使用FutureBuilder和StreamBuilder組件
- 合理的刷新范圍RepaintBoundary
- 避免UI線程耗時操作
- 減少Widget重建
https://flutter.cn/docs/perf/best-practices
main函數(shù)和runApp的區(qū)別?
main函數(shù)是dart的程序運行入口函數(shù)
runApp函數(shù)是渲染根widget樹的函數(shù)
熱重載是如何實現(xiàn)的?
將更新的源代碼文件注入到正在運行的 Dart 虛擬機(VM)來實現(xiàn)熱重載。在虛擬機使用新的字段和函數(shù)更新類之后, Flutter 框架會自動重新構(gòu)建 widget 樹,以便可以快速查看更改的效果。
補充:
熱重載 會將代碼更改轉(zhuǎn)入 VM,重建 widget 樹并保持應(yīng)用的狀態(tài),整個過程不會重新運行 main() 或者 initState()。
熱重啟 會將代碼更改轉(zhuǎn)入 VM,重啟 Flutter 應(yīng)用,不保留應(yīng)用狀態(tài)。
熱重載流程:掃描更新、增量編譯、推送更新、代碼合并、widget重建。
Flutter web 目前僅支持熱重啟,不支持熱重載。
說說flutter里async和await?
await的出現(xiàn)會把await之前和之后的代碼分為兩部分,await并不是程序運行到這里就阻塞了,而是立刻結(jié)束當(dāng)前函數(shù)的執(zhí)行并返回一個Future,函數(shù)內(nèi)剩余代碼通過調(diào)度異步執(zhí)行。
async是和await搭配使用的,await只在async函數(shù)中出現(xiàn)。在async 函數(shù)里可以沒有await或者有多個await。
provider 原理
Provider主要利用了InheritedWidget機制,結(jié)合Listenable監(jiān)聽,在數(shù)據(jù)變化時觸發(fā)創(chuàng)建InheritedWidget,引起InheritedElement的update,從而讓關(guān)聯(lián)的子孫更新。在Provider中封裝了InheritedWidget,持有了model,view通過provider獲取到model,然后操作model。當(dāng)model發(fā)生變化時,通過notify通知Provider更新view。
Provider中消費者Consumer 和 Selector的區(qū)別?
Selector類和Consumer類似,只是對build調(diào)用Widget方法時提供更精細(xì)的控制。支持部分狀態(tài)數(shù)據(jù)更新,才會更新該組件。
四種消費者
Provider.of
Consumer
Selector
InheritedContext:read、watch、selector
八種提供者
1.Provider
2.ChangeNotifierProvider
3.FutureProvider
4.StreamProvider
5.MultiProvider
6.ProxyProvider
7.ChangeNotifierProxyProvider
8.ListenableProxyProvider
getx 原理
Getx 是一個輕量級的狀態(tài)管理庫,它是一個框架級別的解決方案,旨在提高性能和開發(fā)效率。它提供了多種便利功能,例如依賴注入、路由管理、持久化存儲等,使得開發(fā)過程更加高效,結(jié)構(gòu)更加清晰。
- Getx 的核心原理
是使用響應(yīng)式編程模式。在該模式下,數(shù)據(jù)模型是可觀察的,并且任何對模型的更改都會自動反映在視圖中。當(dāng)使用 Getx 時,我們定義數(shù)據(jù)變量作為 Reactive 類型,然后將其添加到相應(yīng)的依賴列表中。當(dāng)模型更改時,依賴列表中的所有組件會被自動通知,以更新它們自己的狀態(tài)。 - Getx 依賴注入機制
通過該機制,我們可以將一個對象或函數(shù)注入到其他組件中,以節(jié)省內(nèi)存和代碼復(fù)雜性。我們可以將實例作為單例或原型進(jìn)行注冊。在編寫組件時,我們只需在構(gòu)造函數(shù)中添加 Get 類型,然后注入所需的依賴項即可。 - Getx 路由管理功能
可以輕松地實現(xiàn)頁面間的導(dǎo)航和傳遞參數(shù)。它使用命名路由技術(shù),使得鏈接和視圖之間的映射更加清晰。我們可以使用路由中間件將路由與頁面動畫和其他自定義功能捆綁在一起。 - Getx 持久化存儲功能,該功能可在應(yīng)用程序關(guān)閉后保存狀態(tài),以便在下次啟動時進(jìn)行恢復(fù)。它使用本地存儲機制,如 SharedPreferences 和 SQLite,以提供跨設(shè)備和跨瀏覽器的一致性。
- 總的來說,Getx 的原理是基于響應(yīng)式編程模式,并提供了依賴注入、路由管理、持久化存儲等多種實用性功能。它通過聚焦于基礎(chǔ)應(yīng)用程序構(gòu)建塊來提高性能和可維護性,使得開發(fā)人員可以更加專注于應(yīng)用程序邏輯和用戶體驗
DevTools
- Flutter widget inspector:了解現(xiàn)有布局、診斷布局問題
flutter WebView加載內(nèi)容過多導(dǎo)致app崩潰
flutter項目中遇到什么影響比較大的問題?
apk瘦身
- 清除無用資源
- 圖片壓縮
- 混淆
- 分架構(gòu)構(gòu)建apk
- 靜態(tài)資源動態(tài)下發(fā)
上傳的圖片特別大,在朋友圈顯示圖片時如何處理性能問題?
- 根據(jù)圖片顯示大小裁剪。設(shè)置Image組件的
cacheWidth和cacheHeight屬性,可以讓引擎以指定的大小解析圖片,減少內(nèi)存的消耗 - 使用cached_network_image插件或者ImageCache類做圖片緩存,避免頻繁請加載圖片資源。
- 上傳圖片時進(jìn)行適當(dāng)壓縮
- 使用占位圖組件FadeInImage和圖片預(yù)加載precacheImage來提高用戶體驗。
- Element復(fù)用優(yōu)化
短視頻切換如何保證流暢播放?
預(yù)加載、隊列
apk安全
- 代碼混淆
- 圖片音視頻資源使用資源加密技術(shù)對資源進(jìn)行加密,運行時動態(tài)解密
- 加固保簽名
圖片性能優(yōu)化
問題1:APP 頁面偶現(xiàn)卡頓,上下滑動不流暢,影響體驗
問題2:devtools查看內(nèi)存,內(nèi)存占用高
優(yōu)化方向:降內(nèi)存、降刷新
高內(nèi)存定位:
通過 Xcode 性能調(diào)試窗口可知,iOS 端智家 APP 的運行內(nèi)存 1.36G 左右;
通過 Android Studio 的 profile 窗口可知,Android 端智家 APP 的運行內(nèi)存在 1.6G 左右;
圖片過載檢測:debug模式下, Flutter Inspector,點擊 Highlight Oversized Images。查看過載檢測日志,很多圖片存在過載,需內(nèi)存優(yōu)化。紅色日志會打印某一張圖的圖片尺寸。
內(nèi)存檢測:profile構(gòu)建模式下,在devtools上查看RSS(resident set size)內(nèi)存占用情況,啟動起來高達(dá)480M左右,在滑動列表時,列表會白屏,內(nèi)存瞬間達(dá)到712M。performance工具查看UI線程繪制時間最高達(dá)40ms。
方案:
- 網(wǎng)絡(luò)圖片壓縮
圖片存放在阿里云 oss 服務(wù)器,可以使用 oss 圖片壓縮參數(shù),采用指定寬高縮放的方式,阿里云還支持百分比縮放。再次檢測 APP 的運行時內(nèi)存占用,內(nèi)存下降到206M。 - 本地圖片壓縮
根據(jù)官方文檔說明,以及圖片過載檢測控制臺優(yōu)化提示,給本地圖片增加 cacheHight 或 cacheWidth;或使用 ResizeImage 組件包裹。
cacheWidth/cacheHight = width/height * 像素密度
降低頁面刷新:局部 UI 刷新 導(dǎo)致重繪;大量邏輯計算驅(qū)動頁面刷新
定位:Flutter Inspector - Highlight Repaints,UI 組件周邊會出現(xiàn)彩色邊框,UI 重繪時彩色邊框會動態(tài)變色。
方案:
- 組件重會
根據(jù)官方性能優(yōu)化指南,出現(xiàn)組件重繪,使用RepaintBoundary包裹組件,缺點是會增加一定的內(nèi)存消耗。我們采用了Provider來實現(xiàn)局部刷新。 - 訂閱關(guān)系的優(yōu)化
頁面在前臺顯示時,才通知狀態(tài)變化去更新UI;不在前臺時,此時不去通知狀態(tài)的變化
推送
極光推送、支持iOS
flutter app?;?/h2>
- 使用前臺服務(wù):flutter_foreground_plugin
- 設(shè)置鬧鐘,進(jìn)程被殺,鬧鐘也會觸發(fā):android_alarm_manager_plus
- 后臺任務(wù): workmanager
- 廠商推送:firebase_messaging
接口加密
使用RSA非對稱加密,服務(wù)器生成公鑰和私鑰,客戶端拿到公鑰對接口參數(shù)加密,然后發(fā)起請求,服務(wù)器使用私鑰對加密報文進(jìn)行解密,獲得原始請求報文。服務(wù)器處理請求,并將響應(yīng)數(shù)據(jù)進(jìn)行加密返回給客戶端,客戶端使用相同的公鑰進(jìn)行解密,獲取結(jié)果。
內(nèi)存優(yōu)化
圖片
釋放不需要的對象
GooglePlay上架流程
https://blog.csdn.net/cuckoosusu/article/details/137172929
https://blog.csdn.net/u012378566/article/details/129749017
Google可能會對以下這幾個方面進(jìn)行檢查。
① 內(nèi)容審查:Google的審核系統(tǒng)會檢測是否含有違反版權(quán)、成人內(nèi)容、暴力內(nèi)容等違禁元素。
② 權(quán)限隱私合理性審查:審查應(yīng)用請求的權(quán)限,例如,一個手電筒應(yīng)用若要求訪問你的通訊錄,這顯然是不合理的。如果應(yīng)用請求的權(quán)限超出其功能所必需的范圍,可能會被拒審。
③ 代碼安全審查:對應(yīng)用程序進(jìn)行分析,檢查應(yīng)用的源代碼、二進(jìn)制文件和資源文件,是否存在惡意代碼、安全漏洞或其他安全風(fēng)險,并進(jìn)行標(biāo)記。
④ 模擬應(yīng)用操作行為:通過模擬操作應(yīng)用的網(wǎng)絡(luò)行為、API調(diào)用行為、日志篩選等一系列操作,提取關(guān)鍵信息進(jìn)行標(biāo)記后,與谷歌龐大的數(shù)據(jù)庫進(jìn)行檢索匹配,以判斷是否存在與已被標(biāo)記的不合規(guī)產(chǎn)品高度相似的情況,從而判斷是否存在違規(guī)行為并決定是否能夠通過審核。
⑤ 應(yīng)用界面規(guī)則
谷歌應(yīng)用商店上架應(yīng)用程序需要符合以下界面規(guī)則:
(1)應(yīng)用界面需要簡潔、清晰、易于使用。
(2)應(yīng)用界面需要符合 Android 設(shè)備的屏幕大小和分辨率。
(3)應(yīng)用界面需要符合 Android 設(shè)備的操作方式和交互習(xí)慣。
⑥應(yīng)用廣告規(guī)則
谷歌應(yīng)用商店上架應(yīng)用程序需要符合以下廣告規(guī)則:
(1)應(yīng)用廣告需要符合谷歌廣告政策,不得包含欺詐、虛假、誤導(dǎo)等內(nèi)容。
(2)應(yīng)用廣告需要標(biāo)明廣告的來源和性質(zhì),不得誤導(dǎo)用戶。
(3)應(yīng)用廣告需要保證廣告內(nèi)容與應(yīng)用內(nèi)容相關(guān)聯(lián)。
IOS應(yīng)用上架AppStore的流程
https://blog.csdn.net/hepingdev/article/details/125522207
自動化打包、渠道打包
https://blog.csdn.net/sugoods/article/details/123508277
利用Flutter 命令工具自定義參數(shù)的功能 --dart-define。
項目中創(chuàng)建腳本shell/xx.sh