Flutter開發環境搭建與工具鏈

Flutter開發實戰

第1章:Flutter開發環境搭建與工具鏈

1.1 Flutter簡介與優勢

Flutter是Google推出的開源UI工具包,用于從單一代碼庫構建編譯為原生性能的移動、Web和桌面應用程序。Flutter的核心優勢包括:

  • 跨平臺一致性:一套代碼運行在iOS、Android、Web、Desktop
  • 高性能:直接編譯為原生ARM代碼,無需JavaScript橋接
  • 熱重載:快速開發調試,提升開發效率
  • 豐富的UI組件:Material Design和Cupertino風格組件
  • 活躍的生態:Google支持,社區活躍,插件豐富

1.2 Flutter SDK安裝與配置

1.2.1 Windows環境安裝

系統要求:

  • Windows 10或更高版本(64位)
  • 磁盤空間:1.64GB(不包括IDE/工具的磁盤空間)
  • Git for Windows

安裝步驟:

  1. 下載Flutter SDK
# 方法1:直接下載壓縮包
# 訪問 https://flutter.dev/docs/get-started/install/windows
# 下載flutter_windows_3.16.0-stable.zip# 方法2:使用Git克隆(推薦)
git clone https://github.com/flutter/flutter.git -b stable
  1. 解壓并配置環境變量
# 解壓到合適目錄,如:C:\flutter
# 添加C:\flutter\bin到系統PATH環境變量
  1. 驗證安裝
flutter --version
flutter doctor

常見問題解決:

# 問題:'flutter' 不是內部或外部命令
# 解決:檢查PATH環境變量是否正確添加Flutter的bin目錄# 問題:網絡連接問題
# 解決:配置鏡像源
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
1.2.2 macOS環境安裝

系統要求:

  • macOS 10.14或更高版本
  • 磁盤空間:2.8GB
  • Xcode(用于iOS開發)

安裝步驟:

  1. 使用Homebrew安裝(推薦)
# 安裝Homebrew(如果未安裝)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"# 安裝Flutter
brew install --cask flutter# 或者手動下載
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_3.16.0-stable.zip
unzip flutter_macos_3.16.0-stable.zip
  1. 添加到PATH
# 編輯shell配置文件(~/.zshrc 或 ~/.bash_profile)
export PATH="$PATH:/path/to/flutter/bin"# 重新加載配置
source ~/.zshrc
  1. 配置iOS開發環境
# 安裝Xcode
# 從App Store安裝Xcode# 安裝Xcode命令行工具
sudo xcode-select --install# 同意Xcode許可證
sudo xcodebuild -license accept
1.2.3 Linux環境安裝

系統要求:

  • Linux(64位)
  • 依賴庫:bash、curl、file、git、mkdir、rm、unzip、which、xz-utils

安裝步驟:

  1. 安裝依賴
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install curl git unzip xz-utils zip libglu1-mesa# CentOS/RHEL
sudo yum install curl git unzip xz zip mesa-libGLU
  1. 下載并安裝Flutter
# 下載Flutter
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.16.0-stable.tar.xz# 解壓
tar xf flutter_linux_3.16.0-stable.tar.xz# 添加到PATH
export PATH="$PATH:`pwd`/flutter/bin"

1.3 開發環境配置

1.3.1 Android Studio配置

安裝Android Studio:

  1. 下載并安裝Android Studio
  2. 啟動Android Studio,完成初始設置
  3. 安裝Flutter和Dart插件

配置步驟:

# 1. 打開Android Studio
# 2. 進入Preferences/Settings -> Plugins
# 3. 搜索并安裝Flutter插件(會自動安裝Dart插件)
# 4. 重啟Android Studio

Android SDK配置:

# 在Android Studio中:
# Tools -> SDK Manager
# 安裝以下組件:
# - Android SDK Platform-Tools
# - Android SDK Build-Tools
# - Android API Level 34(或最新版本)

創建第一個Flutter項目:

// 在Android Studio中創建新項目
// File -> New -> New Flutter Project
// 選擇Flutter Application
// 配置項目名稱和位置// 項目結構說明
flutter_app/
├── android/          # Android原生代碼
├── ios/             # iOS原生代碼
├── lib/             # Dart代碼主目錄
│   └── main.dart    # 應用入口文件
├── test/            # 測試文件
├── web/             # Web平臺支持
├── pubspec.yaml     # 項目配置文件
└── README.md        # 項目說明
1.3.2 VS Code配置

安裝VS Code和插件:

  1. 安裝Visual Studio Code
  2. 安裝必要插件
# 推薦插件列表:
# - Flutter (自動包含Dart插件)
# - Flutter Widget Snippets
# - Awesome Flutter Snippets
# - Dart Data Class Generator
# - Flutter Tree

VS Code配置文件示例:

// .vscode/settings.json
{"dart.flutterSdkPath": "/path/to/flutter","dart.lineLength": 100,"dart.showTodos": true,"dart.openDevTools": "flutter","editor.rulers": [100],"editor.tabCompletion": "on","flutter.debugShowInspectorByDefault": true
}

快捷鍵配置:

// .vscode/keybindings.json
[{"key": "ctrl+f5","command": "flutter.hotReload"},{"key": "ctrl+shift+f5","command": "flutter.hotRestart"}
]

1.4 模擬器與真機調試設置

1.4.1 Android模擬器配置

創建Android虛擬設備:

# 方法1:通過Android Studio創建
# Tools -> AVD Manager -> Create Virtual Device# 方法2:通過命令行創建
# 列出可用的系統鏡像
$ANDROID_HOME/tools/bin/avdmanager list targets# 創建AVD
$ANDROID_HOME/tools/bin/avdmanager create avd -n flutter_emulator -k "system-images;android-34;google_apis;x86_64"# 啟動模擬器
$ANDROID_HOME/emulator/emulator -avd flutter_emulator

模擬器性能優化:

# 啟用硬件加速
# Windows: 確保啟用Hyper-V或HAXM
# macOS: 確保啟用Hypervisor framework
# Linux: 確保啟用KVM# 優化啟動參數
emulator -avd flutter_emulator -gpu host -memory 4096
1.4.2 iOS模擬器配置(僅macOS)
# 啟動iOS模擬器
open -a Simulator# 或通過Xcode啟動
# Xcode -> Developer Tools -> Simulator# 命令行啟動特定設備
xcrun simctl boot "iPhone 15 Pro"
xcrun simctl list devices
1.4.3 真機調試設置

Android真機調試:

# 1. 啟用開發者選項
# 設置 -> 關于手機 -> 連續點擊7次版本號# 2. 啟用USB調試
# 設置 -> 開發者選項 -> USB調試# 3. 連接設備并驗證
adb devices# 4. 安裝應用到設備
flutter run

iOS真機調試:

  1. 配置開發者賬號
  2. 生成證書和描述文件
  3. 在Xcode中配置簽名
# 檢查連接的iOS設備
flutter devices# 運行到iOS設備
flutter run -d [device-id]

常見真機調試問題:

// 問題1:設備未授權
// 解決:檢查設備是否顯示授權彈窗,點擊允許// 問題2:簽名錯誤(iOS)
// 解決:在Xcode中正確配置開發者賬號和簽名證書// 問題3:網絡權限問題
// Android: 在android/app/src/main/AndroidManifest.xml添加
<uses-permission android:name="android.permission.INTERNET" />// iOS: 在ios/Runner/Info.plist添加網絡權限配置

1.5 Flutter Doctor命令詳解

Flutter Doctor是Flutter提供的診斷工具,用于檢查開發環境配置。

基本用法:

# 檢查Flutter環境
flutter doctor# 顯示詳細信息
flutter doctor -v# 檢查特定平臺
flutter doctor --android-licenses

常見輸出解讀:

Doctor summary (to see all details, run flutter doctor -v):
[?] Flutter (Channel stable, 3.16.0, on macOS 14.0, locale zh-CN)
[?] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[?] Xcode - develop for iOS and macOS (Xcode 15.0)
[?] Chrome - develop for the web
[?] Android Studio (version 2023.1)
[?] VS Code (version 1.84.0)
[?] Connected device (2 available)
[?] HTTP Host Availability# 符號說明:
# [?] - 配置正確
# [!] - 有警告,但不影響開發
# [?] - 有錯誤,需要修復

常見問題修復:

# 問題1:Android licenses not accepted
flutter doctor --android-licenses
# 按提示接受所有許可證# 問題2:Xcode not configured
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept# 問題3:Flutter SDK版本過舊
flutter upgrade# 問題4:Dart SDK version不匹配
flutter channel stable
flutter upgrade

1.6 熱重載與熱重啟機制

熱重載(Hot Reload)和熱重啟(Hot Restart)是Flutter開發的核心特性。

1.6.1 熱重載機制原理

熱重載通過以下步驟實現:

  1. 代碼變更檢測:監聽文件系統變化
  2. 增量編譯:只編譯修改的代碼
  3. 狀態保持:保持應用當前狀態
  4. UI更新:重新構建widget樹
// 示例:熱重載演示
import 'package:flutter/material.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Hot Reload Demo',home: CounterPage(),);}
}class CounterPage extends StatefulWidget {@override_CounterPageState createState() => _CounterPageState();
}class _CounterPageState extends State<CounterPage> {int _counter = 0;void _incrementCounter() {setState(() {_counter++; // 修改這里的邏輯,保存文件觸發熱重載});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('熱重載演示'), // 修改這里的文本,觀察熱重載效果backgroundColor: Colors.blue, // 修改顏色測試熱重載),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('按鈕點擊次數:', // 修改這里測試熱重載style: TextStyle(fontSize: 18),),Text('$_counter', // 計數器狀態在熱重載時會保持style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: Icon(Icons.add),),);}
}
1.6.2 熱重載觸發方式
# 方法1:IDE快捷鍵
# Android Studio: Ctrl+\ (Windows/Linux) 或 Cmd+\ (macOS)
# VS Code: Ctrl+F5# 方法2:命令行
flutter run
# 在運行時按 'r' 鍵觸發熱重載
# 在運行時按 'R' 鍵觸發熱重啟# 方法3:自動熱重載
flutter run --hot
1.6.3 熱重載限制與注意事項

不支持熱重載的情況:

// 1. 全局變量和靜態字段
class GlobalData {static int count = 0; // 修改這個值不會熱重載
}// 2. main()函數
void main() {runApp(MyApp()); // 修改這里需要熱重啟
}// 3. initState()方法
class MyWidget extends StatefulWidget {@override_MyWidgetState createState() => _MyWidgetState();
}class _MyWidgetState extends State<MyWidget> {@overridevoid initState() {super.initState();// 修改這里的邏輯需要熱重啟print("Widget initialized");}@overrideWidget build(BuildContext context) {return Container(); // 修改這里可以熱重載}
}// 4. 枚舉類型修改
enum Status { loading, success, error // 添加新的枚舉值需要熱重啟
}

熱重載最佳實踐:

// 1. 合理組織Widget結構
class MyPage extends StatefulWidget {@override_MyPageState createState() => _MyPageState();
}class _MyPageState extends State<MyPage> {// 將UI邏輯拆分成小的方法,便于熱重載測試Widget _buildHeader() {return AppBar(title: Text('我的頁面'),);}Widget _buildBody() {return Center(child: Text('頁面內容'),);}@overrideWidget build(BuildContext context) {return Scaffold(appBar: _buildHeader(),body: _buildBody(),);}
}// 2. 使用const構造函數提高性能
class MyStaticWidget extends StatelessWidget {const MyStaticWidget({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return const Text('靜態內容');}
}

1.7 常見環境問題排查與解決方案

1.7.1 網絡相關問題
# 問題:無法下載依賴包
# 解決方案1:配置鏡像源
flutter pub cache repair# 解決方案2:手動設置代理
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080# 解決方案3:使用國內鏡像
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
1.7.2 權限相關問題
# Android權限問題
# 在android/app/src/main/AndroidManifest.xml中添加權限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /># iOS權限問題
# 在ios/Runner/Info.plist中添加權限說明
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos</string>
1.7.3 構建錯誤解決
// 常見錯誤1:版本沖突
// pubspec.yaml
dependencies:flutter:sdk: fluttersome_package: ^2.0.0 # 確保版本兼容// 解決方案
flutter pub deps // 查看依賴樹
flutter pub upgrade // 升級依賴
flutter clean // 清理構建緩存
flutter pub get // 重新獲取依賴// 常見錯誤2:Gradle構建失敗
// android/build.gradle
buildscript {ext.kotlin_version = '1.8.0' // 更新Kotlin版本dependencies {classpath 'com.android.tools.build:gradle:8.0.0' // 更新Gradle版本}
}

本章小結

本章介紹了Flutter開發環境的完整搭建過程,包括:

  1. 跨平臺SDK安裝:覆蓋Windows、macOS、Linux三大平臺
  2. IDE配置:Android Studio和VS Code的詳細設置
  3. 調試環境:模擬器和真機調試的配置方法
  4. 診斷工具:Flutter Doctor的使用和問題解決
  5. 開發效率:熱重載機制的原理和最佳實踐

練習題

  1. 環境搭建練習

    • 在你的系統上完整安裝Flutter開發環境
    • 使用Flutter Doctor檢查環境配置
    • 創建并運行第一個Flutter應用
  2. 調試環境配置

    • 配置Android模擬器并運行應用
    • 如果有真機,配置真機調試環境
    • 測試熱重載功能
  3. 問題排查練習

    • 故意制造環境問題(如刪除PATH配置)
    • 使用本章方法進行問題排查和修復

思考問題

  1. 為什么Flutter能夠實現熱重載功能?其技術原理是什么?
  2. 在團隊開發中,如何確保所有成員的開發環境一致?
  3. 熱重載和熱重啟的區別是什么?什么情況下必須使用熱重啟?

第2章:Dart語言精要

2.1 Dart語言特性與語法基礎

Dart是Google開發的客戶端優化語言,專為快速應用開發而設計。作為Flutter的編程語言,掌握Dart是Flutter開發的基礎。

2.1.1 Dart語言特點
// Dart語言核心特性演示void main() {// 1. 強類型系統 + 類型推斷String name = "Flutter"; // 顯式類型聲明var age = 25; // 類型推斷,編譯時確定為int// 2. 面向對象編程var person = Person("Alice", 30);person.introduce();// 3. 函數式編程支持var numbers = [1, 2, 3, 4, 5];var doubled = numbers.map((n) => n * 2).toList();print("Doubled: $doubled");// 4. 異步編程原生支持fetchUserData();// 5. 空安全(Null Safety)String? nullableName; // 可空類型String nonNullName = "Flutter"; // 非空類型print("nullableName: $nullableName"); // 輸出: nullprint("nonNullName: $nonNullName");
}// 類定義
class Person {String name;int age;// 構造函數Person(this.name, this.age);// 方法void introduce() {print("Hi, I'm $name, $age years old.");}
}// 異步函數
Future<void> fetchUserData() async {print("Fetching user data...");await Future.delayed(Duration(seconds: 1));print("User data loaded!");
}
2.1.2 基本語法結構

注釋和文檔:

// 單行注釋/*多行注釋可以跨越多行
*//// 文檔注釋 - 用于生成API文檔
/// 這是一個計算函數
/// 
/// [a] 第一個參數
/// [b] 第二個參數
/// 返回兩數之和
int add(int a, int b) {return a + b;
}/*** 傳統的多行文檔注釋* 也被支持*/

基本數據類型:

void main() {// 數字類型int integer = 42;double floating = 3.14;num number = 42; // int和double的父類型// 字符串類型String singleQuote = 'Hello';String doubleQuote = "World";String multiLine = '''這是一個多行字符串''';// 布爾類型bool isTrue = true;bool isFalse = false;// 字符串插值print("Number: $number, Is true: $isTrue");print("Expression: ${1 + 1}");// 原始字符串(不處理轉義字符)String rawString = r'This is a raw string with \n';print(rawString);// 類型檢查和轉換print("integer is int: ${integer is int}");print("integer as num: ${integer as num}");
}

操作符詳解:

void demonstrateOperators() {// 算術操作符int a = 10, b = 3;print("加法: ${a + b}");        // 13print("減法: ${a - b}");        // 7print("乘法: ${a * b}");        // 30print("除法: ${a / b}");        // 3.3333...print("整除: ${a ~/ b}");       // 3print("取模: ${a % b}");        // 1// 比較操作符print("等于: ${a == b}");       // falseprint("不等于: ${a != b}");      // trueprint("大于: ${a > b}");        // trueprint("小于等于: ${a <= b}");    // false// 邏輯操作符bool x = true, y = false;print("邏輯與: ${x && y}");      // falseprint("邏輯或: ${x || y}");      // trueprint("邏輯非: ${!x}");         // false// 位操作符int m = 5, n = 3; // 101, 011 in binaryprint("按位與: ${m & n}");       // 1 (001)print("按位或: ${m | n}");       // 7 (111)print("按位異或: ${m ^ n}");      // 6 (110)print("按位取反: ${~m}");        // -6print("左移: ${m << 1}");       // 10print("右移: ${m >> 1}");       // 2// 賦值操作符int value = 10;value += 5;  // value = value + 5print("加法賦值: $value");       // 15value *= 2;  // value = value * 2print("乘法賦值: $value");       // 30// 空合并操作符String? nullableString;String result = nullableString ?? "默認值";print("空合并: $result");        // 默認值// 條件表達式int score = 85;String grade = score >= 90 ? "A" : score >= 80 ? "B" : "C";print("等級: $grade");          // B// 級聯操作符var list = <int>[]..add(1)..add(2)..add(3);print("級聯操作: $list");        // [1, 2, 3]
}

2.2 變量、函數、類與繼承

2.2.1 變量聲明與作用域
// 全局變量
String globalVar = "I'm global";
late String lateGlobalVar; // 延遲初始化void main() {// 局部變量聲明方式// 1. 顯式類型聲明int explicitInt = 42;String explicitString = "Hello";// 2. 類型推斷var inferredInt = 42; // 推斷為intvar inferredString = "Hello"; // 推斷為String// 3. 動態類型dynamic dynamicVar = 42;dynamicVar = "Now I'm a string"; // 可以改變類型// 4. 常量聲明const int constantInt = 42; // 編譯時常量final int finalInt = DateTime.now().millisecondsSinceEpoch; // 運行時常量// 5. 可空類型int? nullableInt; // 可以為nullint nonNullableInt = 42; // 不能為null// 作用域演示{String blockScoped = "I'm in a block";print(blockScoped); // 可以訪問}// print(blockScoped); // 錯誤:超出作用域// Late變量使用late String expensiveString;// 只有在需要時才初始化if (someCondition()) {expensiveString = performExpensiveOperation();print(expensiveString);}
}bool someCondition() => true;
String performExpensiveOperation() => "Expensive result";// 變量的獲取器和設置器
class Rectangle {double _width = 0;double _height = 0;// 獲取器double get area => _width * _height;// 設置器set width(double value) {if (value < 0) {throw ArgumentError("Width cannot be negative");}_width = value;}set height(double value) {if (value < 0) {throw ArgumentError("Height cannot be negative");}_height = value;}double get width => _width;double get height => _height;
}
2.2.2 函數定義與調用
// 函數定義的各種形式
void main() {// 調用各種函數print("基本函數: ${basicFunction(5, 3)}");print("可選參數: ${optionalParameters(10)}");print("命名參數: ${namedParameters(a: 5, b: 3)}");print("默認參數: ${defaultParameters(10)}");// 匿名函數和箭頭函數var anonymousFunction = (int x) {return x * x;};var arrowFunction = (int x) => x * x;print("匿名函數: ${anonymousFunction(5)}");print("箭頭函數: ${arrowFunction(5)}");// 高階函數示例var numbers = [1, 2, 3, 4, 5];var processed = processNumbers(numbers, (x) => x * 2);print("高階函數: $processed");// 閉包示例var multiplier = createMultiplier(3);print("閉包: ${multiplier(4)}"); // 12
}// 1. 基本函數
int basicFunction(int a, int b) {return a + b;
}// 2. 可選位置參數
int optionalParameters(int a, [int? b, int c = 10]) {return a + (b ?? 0) + c;
}// 3. 命名參數
int namedParameters({required int a, int b = 0}) {return a + b;
}// 4. 默認參數值
int defaultParameters(int a, {int b = 5, int c = 10}) {return a + b + c;
}// 5. 高階函數(函數作為參數)
List<int> processNumbers(List<int> numbers, int Function(int) processor) {return numbers.map(processor).toList();
}// 6. 閉包
Function createMultiplier(int factor) {return (int value) => value * factor;
}// 7. 生成器函數
Iterable<int> naturalNumbers(int max) sync* {int current = 1;while (current <= max) {yield current++;}
}// 8. 異步生成器函數
Stream<int> asynchronousNaturals(int max) async* {int current = 1;while (current <= max) {await Future.delayed(Duration(milliseconds: 100));yield current++;}
}// 函數類型定義
typedef Calculator = int Function(int a, int b);
typedef StringProcessor = String Function(String input);// 使用函數類型
class MathUtils {static Calculator adder = (a, b) => a + b;static Calculator multiplier = (a, b) => a * b;static int calculate(int a, int b, Calculator calc) {return calc(a, b);}
}
2.2.3 類的定義與使用
// 基礎類定義
class Animal {// 私有屬性(以_開頭)String _name;int _age;// 公共屬性String species;// 構造函數Animal(this._name, this._age, this.species);// 命名構造函數Animal.baby(String name, String species) : _name = name,_age = 0,species = species;// 工廠構造函數factory Animal.fromJson(Map<String, dynamic> json) {return Animal(json['name'], json['age'], json['species']);}// 獲取器和設置器String get name => _name;int get age => _age;set name(String newName) {if (newName.isNotEmpty) {_name = newName;}}// 方法void makeSound() {print("$_name makes a sound");}void eat(String food) {print("$_name is eating $food");}// 靜態方法static Animal createRandomAnimal() {var names = ['Buddy', 'Max', 'Luna'];var species = ['Dog', 'Cat', 'Bird'];return Animal(names[DateTime.now().millisecond % names.length],DateTime.now().millisecond % 10,species[DateTime.now().millisecond % species.length]);}// 重寫toString方法@overrideString toString() {return 'Animal{name: $_name, age: $_age, species: $species}';}
}// 繼承
class Dog extends Animal {String breed;// 調用父類構造函數Dog(String name, int age, this.breed) : super(name, age, 'Dog');// 重寫方法@overridevoid makeSound() {print("$name barks: Woof! Woof!");}// 新增方法void fetch() {print("$name is fetching the ball");}// 方法重載(Dart不支持真正的重載,但可以用可選參數實現)void playWith([String? toy]) {if (toy != null) {print("$name is playing with $toy");} else {print("$name is playing");}}
}// 抽象類
abstract class Shape {// 抽象方法double calculateArea();double calculatePerimeter();// 具體方法void displayInfo() {print("Area: ${calculateArea()}, Perimeter: ${calculatePerimeter()}");}
}// 實現抽象類
class Circle extends Shape {double radius;Circle(this.radius);@overridedouble calculateArea() {return 3.14159 * radius * radius;}@overridedouble calculatePerimeter() {return 2 * 3.14159 * radius;}
}// 接口(在Dart中通過abstract class或普通class實現)
abstract class Flyable {void fly();
}abstract class Swimmable {void swim();
}// 多重繼承(通過mixin實現)
mixin CanFly {void fly() {print("Flying in the sky");}
}mixin CanSwim {void swim() {print("Swimming in water");}
}// 使用mixin
class Duck extends Animal with CanFly, CanSwim {Duck(String name, int age) : super(name, age, 'Duck');@overridevoid makeSound() {print("$name quacks: Quack! Quack!");}
}// 使用示例
void main() {// 創建對象var dog = Dog("Buddy", 3, "Golden Retriever");dog.makeSound();dog.fetch();dog.playWith("ball");// 多態Animal animal = Dog("Max", 2, "Bulldog");animal.makeSound(); // 調用Dog的重寫方法// 抽象類Shape circle = Circle(5.0);circle.displayInfo();// Mixin使用var duck = Duck("Donald", 5);duck.makeSound();duck.fly();duck.swim();// 工廠構造函數var animalFromJson = Animal.fromJson({'name': 'Whiskers','age': 4,'species': 'Cat'});print(animalFromJson);
}

2.3 異步編程:Future、async/await、Stream

異步編程是Dart和Flutter的核心特性,用于處理網絡請求、文件操作、定時器等耗時操作。

2.3.1 Future基礎
import 'dart:async';
import 'dart:math';void main() async {print("=== Future基礎演示 ===");// 基本Future使用await demonstrateFutureBasics();// Future錯誤處理await demonstrateFutureErrorHandling();// Future組合操作await demonstrateFutureCombination();
}// Future基礎用法
Future<void> demonstrateFutureBasics() async {print("\n1. 基礎Future操作:");// 方式1: 使用then()fetchUserData(1).then((user) {print("用戶信息: $user");});// 方式2: 使用async/await (推薦)String user = await fetchUserData(2);print("用戶信息: $user");// 方式3: 創建立即完成的FutureFuture<String> immediateFuture = Future.value("立即返回的值");String result = await immediateFuture;print("立即結果: $result");// 方式4: 延遲Futureprint("開始延遲操作...");await Future.delayed(Duration(seconds: 1), () {print("延遲操作完成!");});
}// 模擬異步獲取用戶數據
Future<String> fetchUserData(int userId) async {// 模擬網絡延遲await Future.delayed(Duration(milliseconds: 500));// 模擬隨機失敗if (Random().nextBool()) {throw Exception("網絡錯誤: 無法獲取用戶 $userId 的數據");}return "User$userId{name: '張三', age: 25}";
}// Future錯誤處理
Future<void> demonstrateFutureErrorHandling() async {print("\n2. Future錯誤處理:");// 方式1: try-catchtry {String userData = await fetchUserData(3);print("成功獲取: $userData");} catch (e) {print("捕獲異常: $e");}// 方式2: catchErrorfetchUserData(4).then((user) => print("成功: $user")).catchError((error) => print("失敗: $error"));// 方式3: 超時處理try {String result = await fetchUserData(5).timeout(Duration(milliseconds: 200),onTimeout: () => throw TimeoutException("請求超時", Duration(milliseconds: 200)),);print("超時測試成功: $result");} on TimeoutException catch (e) {print("請求超時: ${e.message}");} catch (e) {print("其他錯誤: $e");}
}// Future組合操作
Future<void> demonstrateFutureCombination() async {print("\n3. Future組合操作:");// 并行執行多個FutureList<Future<String>> futures = [fetchData("API1", 300),fetchData("API2", 500),fetchData("API3", 200),];// 等待所有Future完成try {List<String> results = await Future.wait(futures);print("所有請求完成: $results");} catch (e) {print("有請求失敗: $e");}// 只要有一個完成就返回String firstResult = await Future.any(futures);print("最快完成的請求: $firstResult");// 鏈式操作String chainResult = await fetchData("初始數據", 100).then((data) => processData(data)).then((processed) => saveData(processed));print("鏈式操作結果: $chainResult");
}// 輔助函數
Future<String> fetchData(String source, int delay) async {await Future.delayed(Duration(milliseconds: delay));if (Random().nextDouble() < 0.2) { // 20%失敗率throw Exception("$source 請求失敗");}return "$source 的數據";
}Future<String> processData(String data) async {await Future.delayed(Duration(milliseconds: 100));return "處理后的 $data";
}Future<String> saveData(String data) async {await Future.delayed(Duration(milliseconds: 50));return "已保存: $data";
}
2.3.2 Stream詳解
import 'dart:async';void main() async {print("=== Stream演示 ===");// 基礎Stream操作await demonstrateStreamBasics();// Stream變換和過濾await demonstrateStreamTransformation();// 自定義Streamawait demonstrateCustomStream();// StreamController使用await demonstrateStreamController();
}// Stream基礎操作
Future<void> demonstrateStreamBasics() async {print("\n1. Stream基礎操作:");// 創建簡單的StreamStream<int> numberStream = Stream.fromIterable([1, 2, 3, 4, 5]);// 方式1: 使用listenprint("使用listen監聽:");numberStream.listen((number) => print("接收到: $number"),onError: (error) => print("錯誤: $error"),onDone: () => print("Stream完成"),);// 等待一段時間讓上面的Stream完成await Future.delayed(Duration(milliseconds: 100));// 方式2: 使用await for (推薦)print("\n使用await for:");await for (int number in Stream.fromIterable([6, 7, 8, 9, 10])) {print("處理數字: $number");}
}// Stream變換和過濾
Future<void> demonstrateStreamTransformation() async {print("\n2. Stream變換和過濾:");// 創建數字流Stream<int> numbers = Stream.periodic(Duration(milliseconds: 200),(index) => index + 1,).take(10); // 只取前10個// 變換操作await for (String result in numbers.where((n) => n % 2 == 0)           // 過濾偶數.map((n) => "偶數: $n")              // 轉換為字符串.take(3)) {                        // 只取前3個print(result);}// 復雜的Stream操作鏈print("\n復雜操作鏈:");await numbers.where((n) => n > 3)                // 大于3.map((n) => n * n)                  // 平方.distinct()                         // 去重.timeout(Duration(seconds: 5))      // 超時處理.handleError((error) {              // 錯誤處理print("Stream錯誤: $error");return -1;}).forEach((value) => print("結果: $value"));
}// 自定義Stream
Future<void> demonstrateCustomStream() async {print("\n3. 自定義Stream:");// 使用async*創建Streamawait for (String data in generateDataStream()) {print("自定義Stream數據: $data");}
}// 生成器函數創建Stream
Stream<String> generateDataStream() async* {for (int i = 1; i <= 5; i++) {await Future.delayed(Duration(milliseconds: 300));yield "數據項 $i";if (i == 3) {yield* generateSubStream(); // 委托給另一個Stream}}
}Stream<String> generateSubStream() async* {yield "子流數據 A";yield "子流數據 B";
}// StreamController使用
Future<void> demonstrateStreamController() async {print("\n4. StreamController使用:");// 創建StreamControllerStreamController<String> controller = StreamController<String>();// 監聽StreamStreamSubscription<String> subscription = controller.stream.listen((data) => print("控制器數據: $data"),onError: (error) => print("控制器錯誤: $error"),onDone: () => print("控制器完成"),);// 添加數據controller.add("消息1");controller.add("消息2");controller.add("消息3");// 模擬延遲添加Timer.periodic(Duration(milliseconds: 500), (timer) {static int count = 0;if (count < 3) {controller.add("定時消息 ${++count}");} else {timer.cancel();controller.close(); // 關閉Stream}});// 等待Stream完成await controller.done;// 清理await subscription.cancel();
}// 實際應用示例:模擬實時數據流
class DataService {static StreamController<Map<String, dynamic>>? _controller;// 獲取實時數據流static Stream<Map<String, dynamic>> get realTimeData {_controller ??= StreamController<Map<String, dynamic>>.broadcast();return _controller!.stream;}// 開始數據流static void startDataStream() {Timer.periodic(Duration(seconds: 2), (timer) {if (_controller?.isClosed ?? true) {timer.cancel();return;}_controller?.add({'timestamp': DateTime.now().toIso8601String(),'value': Random().nextDouble() * 100,'status': Random().nextBool() ? 'active' : 'inactive',});});}// 停止數據流static void stopDataStream() {_controller?.close();_controller = null;}
}

2.4 空安全(Null Safety)詳解

空安全是Dart 2.12引入的重要特性,幫助開發者避免空引用異常。

2.4.1 空安全基礎概念
void main() {print("=== 空安全演示 ===");demonstrateNullSafetyBasics();demonstrateNullableOperators();demonstrateNullAssertions();demonstrateLateVariables();
}// 空安全基礎
void demonstrateNullSafetyBasics() {print("\n1. 空安全基礎:");// 非空類型 - 不能為nullString nonNullableString = "Hello, World!";int nonNullableInt = 42;// 可空類型 - 可以為nullString? nullableString = null;int? nullableInt; // 默認為nullprint("非空字符串: $nonNullableString");print("可空字符串: $nullableString");print("可空整數: $nullableInt");// 編譯時錯誤示例(取消注釋會報錯)// nonNullableString = null; // 錯誤:不能將null賦給非空類型// print(nullableString.length); // 錯誤:可空類型不能直接調用方法// 正確的處理方式if (nullableString != null) {print("字符串長度: ${nullableString.length}"); // 類型提升}
}// 空安全操作符
void demonstrateNullableOperators() {print("\n2. 空安全操作符:");String? nullableString;List<String>? nullableList;// 1. 空感知訪問操作符 (?.)print("安全訪問長度: ${nullableString?.length}"); // 輸出: nullprint("安全訪問第一個元素: ${nullableList?.first}"); // 輸出: null// 2. 空合并操作符 (??)String result = nullableString ?? "默認值";print("空合并結果: $result"); // 輸出: 默認值// 3. 空合并賦值操作符 (??=)nullableString ??= "賦值的默認值";print("空合并賦值: $nullableString"); // 輸出: 賦值的默認值// 4. 級聯空感知操作符 (?..)List<String>? optionalList = ["item1", "item2"];optionalList?..add("item3")..add("item4");print("級聯操作結果: $optionalList");// 5. 空感知索引操作符 (?[])List<String>? items = ["first", "second"];print("安全索引訪問: ${items?[0]}"); // 輸出: firstitems = null;print("空列表安全訪問: ${items?[0]}"); // 輸出: null
}// 空斷言和類型檢查
void demonstrateNullAssertions() {print("\n3. 空斷言和類型檢查:");String? possiblyNullString = "Not null";// 1. 空斷言操作符 (!) - 謹慎使用if (possiblyNullString != null) {String definitelyNotNull = possiblyNullString!;print("斷言非空: $definitelyNotNull");}// 2. 類型檢查和轉換Object? someObject = "Hello";if (someObject is String) {// 類型提升 - someObject現在被認為是String類型print("類型提升: ${someObject.toUpperCase()}");}// 3. 安全類型轉換String? safeString = someObject as String?;print("安全轉換: $safeString");// 4. 復雜的空檢查String? getName() => Random().nextBool() ? "Alice" : null;String name = getName() ?? "Unknown";print("獲取姓名: $name");
}// Late變量
void demonstrateLateVariables() {print("\n4. Late變量:");// Late變量示例late String expensiveValue;late final String computedValue;// 延遲初始化函數String expensiveComputation() {print("執行昂貴的計算...");return "計算結果";}// 只有在訪問時才會初始化print("準備訪問late變量");expensiveValue = expensiveComputation();print("Late變量值: $expensiveValue");// Late final變量computedValue = "一次性計算的值";print("Late final值: $computedValue");// computedValue = "嘗試再次賦值"; // 錯誤:final變量不能重新賦值
}// 實際應用示例
class UserService {// 私有的可空字段User? _currentUser;// 公共的非空訪問器User get currentUser {final user = _currentUser;if (user == null) {throw StateError('沒有當前用戶');}return user;}// 安全的用戶訪問User? get currentUserOrNull => _currentUser;// 登錄方法Future<void> login(String username, String password) async {// 模擬網絡請求await Future.delayed(Duration(seconds: 1));if (username.isNotEmpty && password.isNotEmpty) {_currentUser = User(username, "$username@example.com");} else {throw ArgumentError('用戶名和密碼不能為空');}}// 登出方法void logout() {_currentUser = null;}// 安全的用戶操作String? getUserEmail() {return _currentUser?.email;}// 使用空合并操作符提供默認值String getDisplayName() {return _currentUser?.name ?? '匿名用戶';}
}class User {final String name;final String email;User(this.name, this.email);@overrideString toString() => 'User{name: $name, email: $email}';
}// 空安全最佳實踐示例
class ShoppingCart {final List<CartItem> _items = [];// 安全地添加商品void addItem(String? productName, double? price, int? quantity) {// 使用空檢查和默認值final name = productName?.trim();if (name == null || name.isEmpty) {throw ArgumentError('商品名稱不能為空');}final validPrice = price ?? 0.0;if (validPrice <= 0) {throw ArgumentError('價格必須大于0');}final validQuantity = quantity ?? 1;if (validQuantity <= 0) {throw ArgumentError('數量必須大于0');}_items.add(CartItem(name, validPrice, validQuantity));}// 安全地獲取商品CartItem? getItem(int index) {if (index >= 0 && index < _items.length) {return _items[index];}return null;}// 計算總價double get totalPrice {return _items.fold(0.0, (sum, item) => sum + item.totalPrice);}// 獲取商品數量int get itemCount => _items.length;// 安全地移除商品bool removeItem(String productName) {final index = _items.indexWhere((item) => item.name == productName);if (index != -1) {_items.removeAt(index);return true;}return false;}
}class CartItem {final String name;final double price;final int quantity;CartItem(this.name, this.price, this.quantity);double get totalPrice => price * quantity;@overrideString toString() => '$name x$quantity = \$${totalPrice.toStringAsFixed(2)}';
}

2.5 集合類型與泛型使用

集合類型和泛型是Dart編程的重要組成部分,提供了強大的數據處理能力。

2.5.1 List集合詳解
void main() {print("=== 集合類型演示 ===");demonstrateListOperations();demonstrateSetOperations();demonstrateMapOperations();demonstrateGenerics();
}// List集合操作
void demonstrateListOperations() {print("\n1. List集合操作:");// 創建List的多種方式List<int> numbers1 = [1, 2, 3, 4, 5];List<int> numbers2 = List.filled(5, 0); // [0, 0, 0, 0, 0]List<int> numbers3 = List.generate(5, (index) => index * 2); // [0, 2, 4, 6, 8]List<String> names = <String>['Alice', 'Bob', 'Charlie'];print("numbers1: $numbers1");print("numbers2: $numbers2");print("numbers3: $numbers3");print("names: $names");// 基本操作numbers1.add(6);                    // 添加元素numbers1.addAll([7, 8, 9]);        // 添加多個元素numbers1.insert(0, 0);             // 在指定位置插入print("修改后的numbers1: $numbers1");// 訪問和修改print("第一個元素: ${numbers1.first}");print("最后一個元素: ${numbers1.last}");print("長度: ${numbers1.length}");numbers1[1] = 99; // 修改指定位置的元素print("修改索引1后: $numbers1");// 查找操作print("包含5: ${numbers1.contains(5)}");print("99的索引: ${numbers1.indexOf(99)}");print("大于5的第一個數: ${numbers1.firstWhere((n) => n > 5)}");// 刪除操作numbers1.remove(99);               // 刪除特定值numbers1.removeAt(0);              // 刪除指定索引numbers1.removeLast();             // 刪除最后一個numbers1.removeWhere((n) => n > 7); // 刪除滿足條件的元素print("刪除操作后: $numbers1");// 高級操作List<int> doubled = numbers1.map((n) => n * 2).toList();List<int> evenNumbers = numbers1.where((n) => n % 2 == 0).toList();int sum = numbers1.fold(0, (previous, element) => previous + element);print("翻倍: $doubled");print("偶數: $evenNumbers");print("總和: $sum");// 排序和反轉List<int> unsorted = [3, 1, 4, 1, 5, 9, 2, 6];print("原列表: $unsorted");unsorted.sort(); // 升序排序print("升序: $unsorted");unsorted.sort((a, b) => b.compareTo(a)); // 降序排序print("降序: $unsorted");List<int> reversed = unsorted.reversed.toList();print("反轉: $reversed");// 列表推導式風格操作List<String> words = ['hello', 'world', 'dart', 'flutter'];List<String> upperCased = [for (String word in words)if (word.length > 4)word.toUpperCase()];print("條件轉換: $upperCased");
}// Set集合操作
void demonstrateSetOperations() {print("\n2. Set集合操作:");// 創建SetSet<String> fruits = {'apple', 'banana', 'orange'};Set<String> citrus = {'orange', 'lemon', 'lime'};Set<int> numbers = <int>{1, 2, 3, 4, 5, 1, 2}; // 自動去重print("水果: $fruits");print("柑橘類: $citrus");print("數字(去重): $numbers");// Set操作fruits.add('grape');              // 添加元素fruits.addAll(['mango', 'kiwi']); // 添加多個元素print("添加后的水果: $fruits");// 集合運算Set<String> union = fruits.union(citrus);         // 并集Set<String> intersection = fruits.intersection(citrus); // 交集Set<String> difference = fruits.difference(citrus);    // 差集print("并集: $union");print("交集: $intersection");print("差集: $difference");// 查詢操作print("包含apple: ${fruits.contains('apple')}");print("是否為citrus的子集: ${{'orange', 'lemon'}.containsAll(citrus)}");// 轉換操作List<String> fruitList = fruits.toList();Set<int> lengths = fruits.map((f) => f.length).toSet();print("轉為列表: $fruitList");print("長度集合: $lengths");
}// Map集合操作
void demonstrateMapOperations() {print("\n3. Map集合操作:");// 創建MapMap<String, int> ages = {'Alice': 25,'Bob': 30,'Charlie': 35,};Map<String, String> capitals = Map<String, String>();capitals['China'] = 'Beijing';capitals['USA'] = 'Washington';capitals['Japan'] = 'Tokyo';print("年齡: $ages");print("首都: $capitals");// 基本操作ages['David'] = 28;              // 添加鍵值對ages.putIfAbsent('Eve', () => 32); // 如果不存在則添加print("添加后的年齡: $ages");// 訪問操作print("Alice的年齡: ${ages['Alice']}");print("Frank的年齡: ${ages['Frank']}"); // nullprint("安全獲取年齡: ${ages['Frank'] ?? 0}");// 查詢操作print("包含Alice: ${ages.containsKey('Alice')}");print("包含年齡30: ${ages.containsValue(30)}");print("是否為空: ${ages.isEmpty}");print("鍵: ${ages.keys}");print("值: ${ages.values}");// 遍歷Mapprint("\n遍歷Map:");ages.forEach((name, age) {print("$name is $age years old");});// 高級操作Map<String, String> ageDescriptions = ages.map((name, age) => MapEntry(name, age > 30 ? 'senior' : 'junior'));print("年齡描述: $ageDescriptions");// 過濾操作Map<String, int> seniors = Map.fromEntries(ages.entries.where((entry) => entry.value > 30));print("年長者: $seniors");// 刪除操作ages.remove('Charlie');ages.removeWhere((name, age) => age < 30);print("刪除后的年齡: $ages");
}// 泛型詳解
void demonstrateGenerics() {print("\n4. 泛型使用:");// 泛型類使用Box<String> stringBox = Box<String>("Hello, Generics!");Box<int> intBox = Box<int>(42);print("字符串盒子: ${stringBox.value}");print("整數盒子: ${intBox.value}");// 泛型方法使用List<String> strings = ["apple", "banana", "cherry"];List<int> numbers = [1, 2, 3, 4, 5];String firstString = getFirst<String>(strings);int firstNumber = getFirst<int>(numbers);print("第一個字符串: $firstString");print("第一個數字: $firstNumber");// 約束泛型NumberBox<int> intNumberBox = NumberBox<int>(100);NumberBox<double> doubleNumberBox = NumberBox<double>(3.14);print("整數運算: ${intNumberBox.calculate()}");print("浮點數運算: ${doubleNumberBox.calculate()}");// 通配符和協變List<Animal> animals = <Animal>[Dog("Buddy"), Cat("Whiskers")];printAnimals(animals);List<Dog> dogs = <Dog>[Dog("Max"), Dog("Luna")];printAnimals(dogs); // 協變:List<Dog>可以賦值給List<Animal>
}// 泛型類示例
class Box<T> {T value;Box(this.value);void updateValue(T newValue) {value = newValue;}T getValue() => value;
}// 泛型方法示例
T getFirst<T>(List<T> list) {if (list.isEmpty) {throw ArgumentError("List cannot be empty");}return list.first;
}// 約束泛型示例
class NumberBox<T extends num> {T value;NumberBox(this.value);T calculate() {return value * value as T;}
}// 繼承和泛型
abstract class Animal {String name;Animal(this.name);void makeSound();@overrideString toString() => "$runtimeType: $name";
}class Dog extends Animal {Dog(String name) : super(name);@overridevoid makeSound() {print("$name barks");}
}class Cat extends Animal {  Cat(String name) : super(name);@overridevoid makeSound() {print("$name meows");}
}// 協變示例
void printAnimals(List<Animal> animals) {for (Animal animal in animals) {print(animal);}
}// 實際應用:通用數據倉庫
class Repository<T> {final Map<String, T> _data = {};void save(String id, T item) {_data[id] = item;}T? findById(String id) {return _data[id];}List<T> findAll() {return _data.values.toList();}bool delete(String id) {return _data.remove(id) != null;}void clear() {_data.clear();}int get count => _data.length;
}

2.6 Dart包管理與依賴引入

包管理是Dart生態系統的重要組成部分,pubspec.yaml文件是項目配置的核心。

2.6.1 pubspec.yaml詳解
# pubspec.yaml - Flutter項目配置文件# 項目基本信息
name: flutter_demo_app          # 項目名稱,必須小寫,可以包含下劃線
description: A comprehensive Flutter demo application.  # 項目描述
version: 1.2.3+4               # 版本號(語義版本+構建號)# 環境配置
environment:sdk: '>=3.0.0 <4.0.0'        # Dart SDK版本約束flutter: ">=3.10.0"          # Flutter版本約束# 依賴配置
dependencies:flutter:sdk: flutter               # Flutter SDK依賴# UI和組件cupertino_icons: ^1.0.6     # iOS風格圖標material_design_icons_flutter: ^7.0.7296  # Material圖標# 網絡請求http: ^1.1.0               # HTTP客戶端dio: ^5.3.2                # 強大的HTTP客戶端# 狀態管理provider: ^6.0.5           # 狀態管理bloc: ^8.1.2               # BLoC模式flutter_bloc: ^8.1.3       # Flutter BLoC# 本地存儲shared_preferences: ^2.2.2  # 簡單鍵值存儲sqflite: ^2.3.0            # SQLite數據庫hive: ^2.2.3               # 快速NoSQL數據庫hive_flutter: ^1.1.0# 導航路由go_router: ^12.1.1         # 聲明式路由# 工具類intl: ^0.18.1              # 國際化支持logger: ^2.0.2+1           # 日志工具uuid: ^3.0.7               # UUID生成器# 圖片處理cached_network_image: ^3.3.0  # 網絡圖片緩存image_picker: ^1.0.4          # 圖片選擇器# 權限管理permission_handler: ^11.0.1   # 權限處理# 設備信息device_info_plus: ^9.1.0     # 設備信息package_info_plus: ^4.2.0    # 應用信息# 開發依賴(僅開發時使用)
dev_dependencies:flutter_test:sdk: flutter# 代碼檢查和格式化flutter_lints: ^3.0.0      # 官方代碼規范very_good_analysis: ^5.1.0  # 更嚴格的代碼規范# 代碼生成build_runner: ^2.4.7        # 代碼生成工具json_annotation: ^4.8.1     # JSON序列化注解json_serializable: ^6.7.1   # JSON序列化代碼生成# 測試工具mockito: ^5.4.2             # Mock測試integration_test:           # 集成測試sdk: flutter# 依賴覆蓋(解決版本沖突)
dependency_overrides:# crypto: ^3.0.3# Flutter配置
flutter:uses-material-design: true   # 使用Material Design# 資源文件配置assets:- assets/images/           # 圖片資源目錄- assets/icons/            # 圖標資源目錄- assets/data/             # 數據文件目錄- assets/config/config.json  # 配置文件# 字體配置fonts:- family: CustomFont       # 自定義字體fonts:- asset: assets/fonts/CustomFont-Regular.ttf- asset: assets/fonts/CustomFont-Bold.ttfweight: 700- asset: assets/fonts/CustomFont-Italic.ttfstyle: italic- family: IconFont         # 圖標字體fonts:- asset: assets/fonts/IconFont.ttf# 平臺特定配置
flutter:# 生成本地化文件generate: true# 插件配置plugin:platforms:android:package: com.example.flutter_demopluginClass: FlutterDemoPluginios:pluginClass: FlutterDemoPlugin
2.6.2 包管理命令詳解
// 包管理實際操作演示void main() {print("=== Dart包管理演示 ===");// 這些命令在實際開發中通過終端執行demonstratePackageCommands();demonstratePackageUsage();
}void demonstratePackageCommands() {print("\n常用包管理命令:");/*// 基本命令flutter pub get          // 獲取依賴包flutter pub upgrade      // 升級依賴包flutter pub outdated     // 查看過時的依賴flutter pub deps         // 顯示依賴樹// 添加依賴flutter pub add http                    // 添加運行時依賴flutter pub add dev:build_runner        // 添加開發依賴flutter pub add --dev flutter_test      // 添加開發依賴(另一種方式)// 移除依賴flutter pub remove http                 // 移除依賴// 發布相關flutter pub publish --dry-run          // 預發布檢查flutter pub publish                    // 發布包到pub.dev// 緩存管理flutter pub cache repair              // 修復緩存flutter pub cache clean               // 清理緩存// 全局包管理flutter pub global activate <package>  // 全局激活包flutter pub global deactivate <package> // 全局停用包flutter pub global list               // 列出全局包*/
}// 包使用示例
void demonstratePackageUsage() {print("\n2. 包使用示例:");// 在實際項目中,需要先添加依賴到pubspec.yaml// 然后運行 flutter pub get// 這里只是演示import語法/*// HTTP請求包使用import 'package:http/http.dart' as http;import 'package:dio/dio.dart';// 狀態管理包使用import 'package:provider/provider.dart';import 'package:flutter_bloc/flutter_bloc.dart';// 工具包使用import 'package:intl/intl.dart';import 'package:logger/logger.dart';// 本地存儲包使用import 'package:shared_preferences/shared_preferences.dart';import 'package:sqflite/sqflite.dart';*/
}
2.6.3 實際包使用示例
// 實際項目中的包使用示例// main.dart
import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
// import 'package:logger/logger.dart';
// import 'package:shared_preferences/shared_preferences.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Package Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: PackageDemoPage(),);}
}class PackageDemoPage extends StatefulWidget {@override_PackageDemoPageState createState() => _PackageDemoPageState();
}class _PackageDemoPageState extends State<PackageDemoPage> {// final Logger logger = Logger();String savedData = '';@overridevoid initState() {super.initState();loadSavedData();}// 使用shared_preferences保存和讀取數據Future<void> loadSavedData() async {// final prefs = await SharedPreferences.getInstance();// setState(() {//   savedData = prefs.getString('demo_key') ?? '暫無數據';// });// logger.i('數據加載完成: $savedData');}Future<void> saveData(String data) async {// final prefs = await SharedPreferences.getInstance();// await prefs.setString('demo_key', data);// logger.i('數據已保存: $data');// loadSavedData();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('包使用演示'),),body: Padding(padding: EdgeInsets.all(16.0),child: Column(crossAxisAlignment: CrossAxisAlignment.stretch,children: [Text('已保存的數據:',style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),SizedBox(height: 8),Container(padding: EdgeInsets.all(12),decoration: BoxDecoration(border: Border.all(color: Colors.grey),borderRadius: BorderRadius.circular(8),),child: Text(savedData),),SizedBox(height: 20),ElevatedButton(onPressed: () => saveData('新數據 ${DateTime.now()}'),child: Text('保存新數據'),),SizedBox(height: 20),ElevatedButton(onPressed: () {// 演示網絡請求(需要添加http或dio依賴)// makeNetworkRequest();ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('網絡請求功能需要添加http依賴')),);},child: Text('發起網絡請求'),),],),),);}// 網絡請求示例(需要http包)/*Future<void> makeNetworkRequest() async {logger.i('開始網絡請求...');try {final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));if (response.statusCode == 200) {logger.i('請求成功: ${response.body}');ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('請求成功!')),);} else {logger.e('請求失敗: ${response.statusCode}');}} catch (e) {logger.e('網絡錯誤: $e');ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('網絡請求失敗: $e')),);}}*/
}// 自定義包結構示例
/*
項目結構:
lib/
├── main.dart
├── models/
│   ├── user.dart
│   └── product.dart
├── services/
│   ├── api_service.dart
│   ├── storage_service.dart
│   └── auth_service.dart
├── screens/
│   ├── home_screen.dart
│   ├── profile_screen.dart
│   └── login_screen.dart
├── widgets/
│   ├── custom_button.dart
│   └── loading_indicator.dart
└── utils/├── constants.dart├── helpers.dart└── validators.dart
*/// services/api_service.dart 示例
class ApiService {// static final Dio _dio = Dio();// static final Logger _logger = Logger();static const String baseUrl = 'https://api.example.com';static Future<Map<String, dynamic>> get(String endpoint) async {try {// final response = await _dio.get('$baseUrl$endpoint');// _logger.i('GET $endpoint: ${response.statusCode}');// return response.data;// 模擬返回return {'status': 'success', 'data': {}};} catch (e) {// _logger.e('API Error: $e');throw Exception('網絡請求失敗: $e');}}static Future<Map<String, dynamic>> post(String endpoint, Map<String, dynamic> data) async {try {// final response = await _dio.post('$baseUrl$endpoint', data: data);// _logger.i('POST $endpoint: ${response.statusCode}');// return response.data;// 模擬返回return {'status': 'success', 'data': data};} catch (e) {// _logger.e('API Error: $e');throw Exception('網絡請求失敗: $e');}}
}// utils/constants.dart 示例
class AppConstants {// API相關static const String apiBaseUrl = 'https://api.example.com';static const int apiTimeout = 30000;// 存儲鍵static const String userTokenKey = 'user_token';static const String userDataKey = 'user_data';static const String settingsKey = 'app_settings';// 界面相關static const double defaultPadding = 16.0;static const double borderRadius = 8.0;// 顏色主題static const Color primaryColor = Color(0xFF2196F3);static const Color secondaryColor = Color(0xFF03DAC6);static const Color errorColor = Color(0xFFB00020);
}

本章小結

本章深入介紹了Dart語言的核心特性:

  1. 語言基礎:語法結構、數據類型、操作符
  2. 函數與類:面向對象編程、繼承、多態
  3. 異步編程:Future、Stream、async/await模式
  4. 空安全:現代Dart的重要特性,提高代碼安全性
  5. 集合與泛型:強大的數據處理能力
  6. 包管理:依賴管理和項目配置

練習題

  1. 基礎語法練習

    • 創建一個學生管理系統,包含Student類
    • 實現添加、刪除、查詢學生功能
    • 使用各種集合類型存儲數據
  2. 異步編程練習

    • 模擬網絡請求獲取用戶數據
    • 實現數據緩存機制
    • 處理網絡異常和超時
  3. 空安全練習

    • 重構現有代碼,添加空安全特性
    • 使用各種空安全操作符
    • 處理可空類型的轉換
  4. 包管理練習

    • 創建新的Flutter項目
    • 添加常用依賴包
    • 實現簡單的HTTP請求和本地存儲

思考問題

  1. Dart的異步模型與其他語言(如JavaScript)有什么異同?
  2. 空安全特性如何改善代碼質量和開發體驗?
  3. 在什么場景下應該使用Stream而不是Future?
  4. 如何在團隊開發中管理和同步依賴包版本?
  5. 泛型在實際開發中的最佳實踐是什么?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90200.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90200.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90200.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

io_uring:Linux異步I/O的革命性突破

目錄 1. io_uring是什么&#xff1f; io_uring核心優勢&#xff1a; 2. io_uring核心原理 2.1 雙環形緩沖區設計 2.2 關鍵數據結構 1、完成隊列CQ 2、提交隊列SQ 3、Params 3. io_uring工作流程 3.1 初始化階段 3.2 I/O操作流程 4. C代碼示例&#xff08;原始系統調…

線段樹學習筆記 - 練習題(2)

文章目錄1. 前言2. P3870 [TJOI2009] 開關3. P2184 貪婪大陸4. P1438 無聊的數列5. P1471 方差1. 前言 線段樹系列文章&#xff1a; 線段樹學習筆記。線段樹學習筆記 - 練習題&#xff08;1&#xff09;。 前一篇做了幾道線段樹的題目&#xff0c;這篇文章就繼續看下線段樹的…

Vue狀態管理:Pinia 與 Vuex 的使用方法與對比【文章附有完整案例】

最近在接手vue項目的需求&#xff0c;因為之前一直在做react的需求&#xff0c;日常的vue練習也少了很多&#xff0c;導致現在接手vue項目&#xff0c;很多關于vue的知識點基本上忘得干干凈凈了。但是好在有基礎&#xff0c;重新學也會很快掌握。分享這個過程中的一些復習內容。…

OpenMed 項目深度分析:推動醫療 NLP 領域的開源革命

摘要 醫療人工智能(AI)領域因高質量數據和模型的獲取受限而發展緩慢。OpenMed 項目通過開源超過380個醫療命名實體識別(NER)模型,顯著降低了研究與應用門檻。本文從項目背景、技術優勢、應用場景、實施挑戰及未來展望五個方面,系統分析 OpenMed 的核心價值與潛力,揭示其…

大模型開發

什么是Ai&#xff1f;AI的全拼是(Artificial Intelligence)人工智能&#xff0c;使機器能夠像人類一樣思考、學習和解決問題的技術。在AI的應用情況下我們更多的是學習自然語言處理。在自然語言處理(Natural Language Processing&#xff0c;NLP)中&#xff0c;有一項關鍵技術叫…

【正常配置了beast擴展,phpinfo信息也顯示了,但是就是不運行】

正常配置了beast擴展&#xff0c;phpinfo信息也顯示了&#xff0c;但是就是不運行場景原因解決排查過程擴展場景 項目中使用到了beast進行源碼保護&#xff0c;指定類存在&#xff0c;但是報錯信息提示類找不到&#xff0c;beast擴展添加到了正在運行的php版本下的ext文件夾下…

CRMEB 單商戶PRO多商戶通用去版權教程

CRMEB去版權教程&#xff0c;此教程可根據具體版本進行調整&#xff0c;基本適用次方法。 后端版權修改 修改后端管理底部版權及門店后端管理底部版權。 文件位置 \view\admin\src\components\copyright\index.vue 文件位置 \view\admin\src\router\routes.js 文件位置 \vi…

舊物回收小程序系統開發:重塑舊物回收產業新生態

在傳統觀念中&#xff0c;舊物回收往往給人一種臟亂差、效率低下的印象&#xff0c;回收過程繁瑣&#xff0c;回收渠道有限&#xff0c;導致許多可回收物被浪費。然而&#xff0c;隨著信息技術的飛速發展&#xff0c;舊物回收小程序系統的開發正為這一古老行業帶來前所未有的變…

SSE和WebSocket區別到底是什么

文章目錄SSE 與 WebSocket&#xff1a;深入剖析兩者核心差異核心差異&#xff1a;單向 vs. 雙向通信技術細節對比協議與連接數據格式錯誤處理與可靠性適用場景&#xff1a;何時選擇 SSE&#xff0c;何時選擇 WebSocket&#xff1f;總結SSE 與 WebSocket&#xff1a;深入剖析兩者…

西安電子科技大學金融學431考研經歷分享

考研數學是區分度最大的科目之一&#xff0c;如何高效備考&#xff1f;本文為你推薦多位名師和經典書籍&#xff0c;助你在每個階段都能穩步提升&#xff0c;最終沖刺成功。一、考研數學備考策略教師推薦① 高等數學&#xff1a;② 線性代數&#xff1a;③ 概率論與數理統計&am…

laravel RedisException: Connection refused優雅草PMS項目管理系統報錯解決-以及Redis 詳細指南-優雅草卓伊凡

laravel RedisException: Connection refused優雅草PMS項目管理系統報錯解決-以及Redis 詳細指南-優雅草卓伊凡今天來開始更新pms系統&#xff0c;因為我們ppt上面要做&#xff0c;才發現原來打不開&#xff0c;此前主要是事情太多&#xff0c;我們一直有很多東西擱置解決 Lara…

拉力覆冰在線監測裝置:電力線路安全運行的數字化守衛者

在極端天氣頻發的背景下&#xff0c;輸電線路覆冰災害已成為威脅電網穩定運行的關鍵因素。拉力覆冰在線監測裝置通過數字化技術構建起全天候監測體系&#xff0c;為電力運維提供精準數據支撐。本文從技術實現與實際應用價值角度&#xff0c;解析該裝置的核心功能與行業意義。核…

AI面試如何提升物流行業招聘效率?實戰案例解析

每年秋招季&#xff0c;物流行業都會迎來海量應屆生簡歷涌入。面對業務快速擴張與人才篩選壓力&#xff0c;傳統線下面試流程長、標準模糊、成本高昂等問題愈發凸顯。本文通過兩大物流頭部企業的實戰案例&#xff0c;解析AI面試如何破解招聘困局&#xff0c;實現效率與質量的雙…

【機器學習】組合優化問題combination-optimization概述

博主簡介&#xff1a;努力學習的22級計算機科學與技術本科生一枚&#x1f338;博主主頁&#xff1a; Yaoyao2024往期回顧&#xff1a;【二分圖算法】手把手教你學會&#xff1a;染色法&#xff08;判斷二分圖&#xff09;、匈牙利算法&#xff08;二分圖的最大匹配&#xff09;…

Linux網絡編程-osi、udp

網絡&#xff1a;不同主機&#xff0c;進程間通信達到不同主機之間的困難&#xff1a;解決主機之間的硬件層面的互聯互通解決主機之間的軟件層面的互聯互通廣域網&#xff1a;進行大范圍網絡數據交換IP地址&#xff1a;區分不同主機 唯一的&#xff08;軟件地址&#xff09;MAC…

刪除 XML 格式中雙引號內的空格

要使用 Shell 命令刪除 XML 格式中雙引號內的空格&#xff08;僅處理屬性值中的空格&#xff0c;保留標簽外的空格&#xff09;&#xff0c;可以使用以下 sed 命令&#xff1a; sed -i :loop; s/\("[^"]*\) \([^"]*"\)/\1\2/g; t loop filename.xml命令詳解…

電腦聲音修復?【圖文詳解】電腦沒有聲音?聲音異常

一、問題背景 在使用電腦的過程中&#xff0c;聲音異常是很常見的問題。比如明明打開了音頻文件&#xff0c;卻聽不到任何聲音&#xff1b;或者聲音忽大忽小、伴有雜音&#xff1b;或者更新了聲卡驅動后&#xff0c;電腦播放不了聲音了&#xff1b;還有可能是插入耳機后&#x…

【文獻筆記】ARS: Automatic Routing Solver with Large Language Models

ARS: Automatic Routing Solver with Large Language Models https://github.com/Ahalikai/ARS-Routbench/ ARS&#xff1a;基于大語言模型的自動路由求解器 1. 概述 1.1. 研究背景 車輛路徑問題&#xff08;VRP&#xff09;是一類經典的組合優化問題&#xff0c;廣泛應用于…

RK3568筆記九十:基于web顯示RTSP流

若該文為原創文章,轉載請注明原文出處。 在網上看到個方案,使用web顯示RTSP視頻流,思路是前端傳入RTSP地址,cgi通過FFMPEG接收RTSP流并保存成avi文件,在通過ffmpeg 命令把avi文件保存成mp4文件,前端在播放mp4文件。此方案需要先保存文件,在轉換文件,無法實時播放。 所以…

2025年Flutter開發主流技術棧

2025年Flutter開發主流技術棧 Flutter作為一種高效、跨平臺的移動應用開發框架&#xff0c;近年來在開發者社區中越來越受歡迎。以下是2025年Flutter開發的主流技術棧&#xff0c;涵蓋了從核心框架到開發工具、狀態管理、數據存儲等多個方面。 1. 核心框架 Flutter&#xff1a;…