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;…