用最新的 Dart 版本提升你的 Flutter 應用


摘要

本篇文章深入探討如何運用最新的 Dart 版本來提升你的 Flutter 應用,讓開發變得更高效且易於維護。 歸納要點:

  • Dart 3.4.4 新增的列舉建構函式能顯著提升 Flutter 應用程式的可讀性與維護性,適合於定義複雜數據類型。
  • 利用 Dart 擴充套件型別可以優化 Flutter 應用程式的效能,特別是在處理大型數據集及複雜邏輯時效果顯著。
  • 在 Flutter 中使用 Isolate 不僅提高了效能,也改善了使用者體驗,有助於處理耗時操作如網絡請求和數據處理。
透過這些新功能與最佳實踐,你將能夠打造出更具性能和可讀性的 Flutter 應用程式。


Dart 3.4.4 的列舉建構函式:提升 Flutter 應用開發效率的關鍵

在不斷發展的 Flutter 開發世界中,撰寫高品質的 Dart 程式碼對於建立高效且穩健的應用程式至關重要。隨著目前版本 Dart 3.4.4 的推出,開發者可以利用一些酷炫的新功能和增強特性,顯著提升程式碼的質量與效能。本文將探討三個專家提示,以運用最新的 Dart SDK 來提升您的 Flutter 應用。

Dart 中的列舉(Enums)提供了一種定義固定一組常數值的方法。在 Dart 2.17 之前,若要為列舉新增像字串或物件等關聯值,需要使用 getter 方法和 switch 陳述句。自 Dart 2.17 起,列舉建構函式允許開發者簡化冗長的列舉宣告。我們來看看兩種實現方式!

預設情況下使用具有建構函式的列舉依然保持不變,如以下程式碼片段所示。在這個例子中,name 和 locale 屬性是透過 getter 方法和 switch 陳述句推匯出來的。

enum Langauge {    german,    english,    french,    spanish;     String get name => switch (this) {          german => 'Deutsch',          english => 'English',          french => 'Français',          spanish => 'Español',    };     Locale get locale => switch (this) {          german => const Locale('de', 'DE'),          english => const Locale('en', 'US'),          french => const Locale('fr', 'FR'),          spanish => const Locale('es', 'ES'),    };  } 

雖然功能上可用,但其實不如預期那麼簡潔……不過,Dart 為我們開發者提供了一個解決方案!隨著列舉型建構子的引入,您可以直接將值與每個列舉常數關聯起來。這使得程式碼更加簡潔且易於理解。

enum Language {    german('Deutsch', Locale('de', 'DE')),    english('English', Locale('en', 'US')),    spanish('Español', Locale('es', 'ES')),    french('Français', Locale('fr', 'FR'));     const Language(this.name, this.locale);      final String name;      final Locale locale;  } 

列舉建構函式:提升程式碼可讀性與維護性

嘗試自己動手:在這個例子中,每個列舉(enum)值都直接與其對應的名稱和區域設定相關聯。建構函式用於初始化這些屬性,使程式碼在增加其他欄位時更加易於維護。

列舉建構函式的好處:
可讀性:列舉值與其資料之間的關聯是明確且易於閱讀的。
可維護性:新增或修改列舉值非常簡單,因為所有相關資料都集中在一處。
減少冗餘程式碼:降低了重複使用 switch 語句和 getter 方法的需求。

Dart 3 引入了擴充套件型別(extension types),這是一項強大的功能,允許你擴充套件現有型別,而不需要繁瑣的包裝類別。這使得你的程式碼更為簡潔高效。我們來比較兩種方法,以便更清楚地說明擴充套件型別如何提升效能。

傳統上,為了擴充套件現有物件的功能,您會建立一個包裝類別。這種方法可能會使程式碼庫變得更加複雜。

class PointWrapper {    PointWrapper(this.point);    final Point point;     double calcDistanceTo(Point other) {      final dx = point.x - other.x;      final dy = point.y - other.y;      return sqrt(dx * dx + dy * dy);    }  } 

在這個例子中,PointWrapper 類別被建立以新增不同的計算功能,例如 calcDistanceTo 方法,用於 Point 類別。使用 Wrapper 的方式如下:

const pointA = Point(2, 3);  const pointB = Point(2, 3);  final wrapper = PointWrapper(pointA);  final distance = wrapper.calcDistanceTo(pointB); 

在這裡,我們可以看到兩個點被例項化。一方面,使用 pointA 作為 PointWrapper 例項的參考,另一方面則使用 pointB 來計算這兩個點之間的距離。擴充套件型別允許我們直接對現有型別進行功能擴充套件,從而產生更清晰、更簡潔的程式碼。

extension type PointWrapper(Point point) {    double calcDistanceTo(Point other) {      final dx = point.x - other.x;      final dy = point.y - other.y;      return sqrt(dx * dx + dy * dy);    }  } 

Dart 擴充套件型別:提升 Flutter 應用程式效能的利器

試著自己動手:擴充套件型別的好處:

「擴充套件型別的功能與包裝類似,但不需要建立額外的執行時物件,這在需要包裝大量物件時會變得相當昂貴。由於擴充套件型別僅限靜態並且在執行時被編譯器處理,因此它們基本上是零成本的。」— Dart。Dart 的 Isolates(自 Dart 版本 2.4 引入)提供了一種強大的方式來平行執行程式碼,同時將重計算解除安裝到獨立執行緒中。這確保了主執行緒保持響應,對於 Flutter 應用程式而言尤為重要,以提升效能。我們可以透過比較兩種方法來說明這些好處。

傳統上,你可能會使用 async 和 await 來執行非同步操作。雖然這樣做有效,但並未利用多個執行緒,仍然可能導致主執行緒等待操作完成而無法繼續進行。

[專案1:擴充套件型別與混合型的異同比較]
了解擴充套件型別與混合型之間的區別,以及如何選擇最合適的技術,是開發者必備的重要知識。深入要點包括:
- 擴充套件型別為現有類別新增方法和屬性,而不需修改原始類別,這一點與混合型 (Mixins) 類似,但二者存在關鍵區別:
- 擴充套件型別是靜態的,在編譯時由編譯器處理,而混合型則是動態的,在執行時被應用。
- 擴充套件型別只能新增方法,而不能新增屬性;相比之下,混合型能夠同時新增方法和屬性。
- 擴充套件型別僅能作用於單一個體,而混合型可以應用於多個不同例項。

選擇擴充套件型別或混合型時,需要考慮以下因素:
- 是否需要新增屬性:若需要增加屬性,就必須選用混合型。
- 是否需應用於多個類別:若希望其適用於多個不同顏色,那麼也要使用混合型。
- 是否需要最佳化效能:若更注重效能最佳化,則建議採取擴充套件型別策略。

[專案2:擴充套件型別在 Flutter 開發中的應用]
在 Flutter 開發過程中,有效地使用擴充套件類 型可幫助開發者簡化程式碼結構,提高維護效率。同樣地,它還能減少記憶體佔用,提高整體效能,使得開發更加流暢。因此,在設計大型 Flutter 應用程式時,引入合理配置的擴充套件 類 型是一個值得考慮的重要策略。

總之,理解並善加運用 Dart 的各種特性,包括 擴 展 類 型 和 Isolates,不僅能提高程式碼質量,也可使你的應 用 程式 在面對複雜任務或高負荷情況下保持穩定和高效。」

例如,為了說明目的,我們使用一個非同步函式來從檔案系統中讀取一個龐大的檔案並返回其內容,具體實現如下:

Future readFileAsync(String path) async {    final file = File(path);    final content = await file.readAsString();    return content.trim();  } 

在以下的範例中,loadContent 會呼叫非同步函式來讀取檔案的內容。

void loadContent() async {    const path = 'lib/file.txt';    final content = await readFileAsync(path);  } 

Flutter 中使用 Isolate 提升效能與使用者體驗

它仍然在主執行緒上執行,這可能導致效能問題,特別是當操作耗時較長的時候。Isolate 允許你並行執行 Dart 程式碼。透過使用 Isolate,你可以將繁重的任務分配到獨立的執行緒中,確保主執行緒保持響應能力。Flutter 本身建議,在你的應用程式處理足夠大以至於暫時阻塞其他計算的計算時,應該使用 Isolate。在 Flutter 應用中,最常見的 Isolate 應用範例就是處理那些可能使 UI 無法響應的計算。

從現在開始,使用 Dart 時,只需對程式碼進行輕微更改,就能輕鬆實現這一點。我們只需要呼叫 `Isolate.run()` 並在其中使用我們的非同步函式。

隨著 Flutter 渲染管道最近開始更加積極地利用 Isolate 來最佳化 UI 更新效率,我們看到了一個新的趨勢。例如,Flutter 團隊正在探索將部分 UI 渲染工作分配到獨立的 Isolate 上,使得主執行緒能夠更專注於 UI 邏輯處理,從而進一步提升 UI 的響應速度。這種整合模式預示著未來提升 Flutter 效能的一個關鍵方向。

在將繁重的計算任務分派給 Isolate 後,結合 `FutureBuilder` 進行 UI 更新也非常有效,可以避免 UI 阻塞。`FutureBuilder` 將監控從 Isolate 傳回的結果,在結果更新後動態重新渲染 UI,以保持介面的流暢性。因此,不僅確保了運算效率,也改善了整體使用者體驗。

 void loadContent() async {    const path = 'lib/file.txt';    final content = await Isolate.run(() => readFileAsync(path));  } 

Flutter 效能最佳化:深入探討 Isolates 的應用與優勢

在這個例子中,loadContent 函式利用 Isolates 來讀取檔案。Isolate.run() 方法在一個獨立的執行緒中執行 readFileAsync 函式,透過不阻塞主執行緒來提升效能。新建立的程式擁有自己的堆(heap),這與主執行緒使用的堆是完全不同的。在 Isolates 的文件中提到,沒有明確規定何時必須使用 isolates,但他們列舉了一些情境,在這些情況下使用 isolates 可能會很有幫助:

- 解析和解碼特別大的 JSON 資料塊。
- 處理和壓縮照片、音訊和影片。
- 轉換音訊和影片檔案。
- 在大型列表或檔案系統中進行複雜搜尋和篩選。
- 執行 I/O 操作,例如與資料庫通訊。
- 處理大量網路請求。

值得注意的是,如果您正在使用 Flutter,可以直接使用 Flutter 的 compute 函式,而不是 Isolate.run()。

隨著 Dart VM 資源隔離技術的不斷演進,Isolates 不僅提供了獨立的堆,也實現了其他資源的有效隔離。例如,每個 isolate 擁有自己獨立的執行緒堆疊(Thread Stack),確保一個 isolate 崩潰不會影響其他 isolate 的運作;每個 isolate 使用專屬的記憶體分配器(Memory Allocator),避免不同 isolates 之間出現記憶體競爭;它們透過訊息傳遞(Message Passing)進行通訊,以確保資料安全性和同步。每個 isolate 獨立處理錯誤,有效防止錯誤擴散至其他 isolates。

最新版本的 Dart VM 在資源隔離方面進一步最佳化,例如採用更精細的記憶體分配策略以及更快速的訊息傳遞機制,顯著提升了 Isolates 的效能及安全性。在當今 Flutter 應用開發中,Isolates 更是扮演著不可或缺的重要角色,使得開發者能夠構建高效且響應迅速的應用程式。

Future compute(ComputeCallback callback, M message, {String? debugLabel})

使用隔離的好處
提升效能:將繁重的計算工作轉移至平行執行緒,保持主執行緒的響應性。
增強反應速度:透過防止主執行緒被阻塞,確保介面的流暢更新。
更佳資源利用:充分利用多核處理器以進行任務的平行執行。

Dart 語言中引入的列舉建構函式、擴充套件型別以及 Isolates 功能,為語言帶來了顯著的增強,使開發者能夠撰寫更高效、可讀且易於維護的程式碼。這些改進共同提升了開發者的體驗,使你可以更輕鬆地構建出更穩健、更具效能的應用程式。迎接這些變化,將你的 Dart 和 Flutter 開發實踐提升到一個新的高度。你對這些新特性有何看法?是否已經開始使用它們呢?(作者:Tobias Rump)


JH

專家

相關討論

❖ 相關專欄