本章深入 Flutter 和 Dart 的底层机制,涵盖渲染原理、编译机制、自定义 RenderObject、动画物理模拟、Isolate/FFI 高级主题及 Dart 并发编程进阶。
📋 章节目录
| 节 | 主题 | 核心内容 |
|---|---|---|
| 11.1 | Flutter 渲染原理 | Layer Tree、Skia、Impeller |
| 11.2 | Dart VM 与 AOT/JIT 编译机制 | JIT、AOT、Tree Shaking、Isolate |
| 11.3 | 自定义 RenderObject 与绘制优化 | RenderBox、performLayout、paint |
| 11.4 | Flutter 动画与物理模拟系统 | Spring、Friction、Gravity、Stagger |
| 11.5 | 高级主题:Isolate 与 FFI | compute、Isolate.spawn、dart:ffi |
| 11.6 | Dart 并发编程进阶 | Event Loop、Future、Stream、Zone |
11.1 Flutter 渲染原理
深入理解 Flutter 的渲染机制,有助于在遇到性能问题时做出精准优化,也是理解 CustomPainter、RenderObject 等高级 API 的基础。
一、Layer Tree 与合成流程
1.1 Layer 树结构
Flutter 使用 Layer Tree 来组织绘制命令,在合成阶段交给 GPU:
Layer Tree 示例:
TransformLayer (根)
├── OffsetLayer (App)
│ ├── RepaintBoundaryLayer (MaterialApp)
│ │ ├── PictureLayer (AppBar 绘制)
│ │ └── PictureLayer (Body 绘制)
│ └── OverlayLayer (Dialog/Toast)
└── BackdropFilterLayer (模糊效果)
主要 Layer 类型:
| Layer | 作用 |
|---|---|
PictureLayer |
存储 Canvas 绘制命令(Picture) |
TransformLayer |
变换(旋转/缩放/位移) |
OpacityLayer |
透明度 |
ClipRectLayer |
矩形裁剪 |
BackdropFilterLayer |
模糊/颜色矩阵滤镜 |
ContainerLayer |
组合多个子 Layer |
1.2 合成流程
Dart/UI Thread Raster Thread(GPU Thread)
────────────── ─────────────────────────
build()
→ Widget Tree
layout()
→ RenderObject Tree
paint()
→ Layer Tree(PictureRecorder 记录绘制命令)
│
│ 发送 Layer Tree(跨线程)
▼
Layer Rasterization
→ 遍历 Layer Tree
→ 调用 Skia/Impeller API
→ 生成 GPU 指令
GPU Submission
→ 提交到 GPU 渲染
→ Frame Buffer 显示到屏幕
二、Engine 与 Skia 工作机制
2.1 Skia 的角色
Flutter Engine
↓ Canvas API 调用
Skia(2D Graphics Library)
↓ 生成 GPU 指令
OpenGL / Metal / Vulkan
↓
GPU 渲染 Frame Buffer
↓
显示到屏幕
2.2 Picture 与 Canvas
dart
// Flutter 内部的绘制原理(简化)
final recorder = PictureRecorder();
final canvas = Canvas(recorder);
// 绘制命令被"录制"
canvas.drawRect(...);
canvas.drawCircle(...);
canvas.drawPath(...);
// 录制完成,生成 Picture 对象
final picture = recorder.endRecording();
Picture是一系列绘制命令的快照- 在 Raster Thread 中,Picture 被真正执行以生成像素
- RepaintBoundary 创建独立 Layer,避免局部变化重新执行整个 Picture
2.3 GPU 渲染流程
Skia → GPU
① Vertex 处理:确定几何形状(矩形/圆形/路径的顶点)
② Fragment 处理:确定每个像素的颜色(Shader 着色器)
③ Compositing:合成各 Layer(考虑透明度、混合模式)
④ Frame Buffer:最终像素输出
三、Impeller(新一代渲染)
Skia 问题:
→ Shader 在运行时编译(首次进入页面 Jank)
→ 大量通用代码,难以优化
Impeller 解决方案:
→ 预编译 Shader(打包时完成)
→ 专为 Flutter 设计,代码更精简
→ iOS 已默认使用,Android 逐步迁移
小结
| 概念 | 要点 |
|---|---|
| Layer Tree | 绘制命令的层次结构,交给 GPU 合成 |
| PictureLayer | 存储 Canvas 绘制命令序列 |
| RepaintBoundary | 创建独立 Layer,隔离重绘范围 |
| Skia | 2D 图形库,将 Flutter 命令转为 GPU 指令 |
| Impeller | 新渲染引擎,预编译 Shader,更流畅 |
11.2 Dart VM 与 AOT/JIT 编译机制
Dart 支持两种编译模式,各自在不同场景下发挥优势。理解编译机制有助于优化 App 启动速度和运行性能。
一、JIT(Just-in-Time)--- Debug 模式
JIT 编译:在运行时将 Dart 字节码编译为机器码。
源代码(.dart)
↓ dart2kernel(前端编译)
Kernel 字节码(.dill)
↓ 运行时 JIT 编译
机器码(CPU 执行)
JIT 的优势:
- ✅ Hot Reload:修改代码无需重启,注入新代码字节码
- ✅ Hot Restart:重新创建 State,保留编译结果
- ✅ 启动时不需要完整编译,首次启动快
JIT 的劣势:
- ❌ 性能低于 AOT(有解释执行开销)
- ❌ 包体较大(包含 Dart VM + 字节码)
- ❌ 不适合生产环境
二、AOT(Ahead-of-Time)--- Release 模式
AOT 编译:在打包阶段将 Dart 代码完全编译为目标平台原生机器码。
源代码(.dart)
↓ CFE(Common Front End)
↓ TFA(Type Flow Analysis)、Tree Shaking
优化后的 Kernel IR
↓ AOT 编译器
目标平台机器码
Android:.so 文件(arm64-v8a / armeabi-v7a / x86_64)
iOS:原生框架(App.framework)
AOT 的优势:
- ✅ 性能接近 C/C++ 原生代码
- ✅ 启动时无需 JIT 预热
- ✅ 包体更小(Tree Shaking 移除未使用代码)
- ✅ 内存更可预测
AOT 的劣势:
- ❌ 不支持 Hot Reload
- ❌ 编译时间较长
三、Tree Shaking
Tree Shaking 工作原理:
从入口(main())开始,静态分析调用图
→ 标记所有可达的类/函数/变量
→ 移除所有未被引用的代码
效果:
导入了 flutter/material.dart(数万行代码)
→ 只有实际使用的 Widget 被编译进包
四、Isolate 内存模型
Dart Isolate 特点:
├── 每个 Isolate 有独立的堆内存
├── Isolate 之间不共享内存(无竞争条件)
├── 通过消息传递(SendPort/ReceivePort)通信
└── 消息需要序列化/反序列化
Flutter 线程与 Isolate:
UI Isolate(主 Isolate):所有 Widget/State 运行在此
compute():创建临时 Isolate 执行耗时任务
Isolate.spawn():创建持久后台 Isolate
五、编译模式对比
| 特性 | Debug(JIT) | Profile | Release(AOT) |
|---|---|---|---|
| 编译方式 | JIT | AOT | AOT |
| 性能 | 低 | 接近 Release | 最高 |
| Hot Reload | ✅ | ❌ | ❌ |
| 断言(assert) | ✅ 开启 | ❌ | ❌ |
| 调试信息 | 完整 | 部分 | 无(混淆后) |
| 适用场景 | 开发调试 | 性能分析 | 生产发布 |
bash
flutter run # Debug(JIT)
flutter run --profile # Profile(AOT,接近生产)
flutter run --release # Release(AOT,完整优化)
小结
| 概念 | 要点 |
|---|---|
| JIT | 运行时编译,支持 Hot Reload,开发模式使用 |
| AOT | 提前编译为机器码,生产模式使用,性能最优 |
| Tree Shaking | 移除未使用代码,减小包体积 |
| Isolate | 独立内存堆,消息通信,无共享状态 |
11.3 自定义 RenderObject 与绘制优化
当 Widget 层无法满足性能要求时,可以直接实现 RenderObject,跳过 Widget/Element 层的开销,获得最优绘制性能。
一、RenderObject 体系
Widget(不可变描述)
↓ createElement()
Element(可变实例)
↓ createRenderObject()
RenderObject(布局与绘制)
常用 RenderObject 基类:
| 基类 | 说明 |
|---|---|
RenderBox |
盒模型布局(最常用) |
RenderSliver |
Sliver 布局(滚动列表) |
RenderProxyBox |
代理式,包裹单子节点 |
RenderShiftedBox |
带偏移的单子节点 |
二、自定义 RenderBox
dart
// 自定义圆形进度条 RenderObject
class CircularProgressRenderBox extends RenderBox {
double _progress;
Color _foregroundColor;
Color _backgroundColor;
double _strokeWidth;
CircularProgressRenderBox({
required double progress,
required Color foregroundColor,
Color backgroundColor = const Color(0xFFE0E0E0),
double strokeWidth = 8,
}) : _progress = progress,
_foregroundColor = foregroundColor,
_backgroundColor = backgroundColor,
_strokeWidth = strokeWidth;
set progress(double value) {
if (_progress == value) return;
_progress = value;
markNeedsPaint(); // 仅重绘,不重新布局
}
set strokeWidth(double value) {
if (_strokeWidth == value) return;
_strokeWidth = value;
markNeedsLayout(); // 影响尺寸,需要重新布局
}
@override
void performLayout() {
final double size = constraints.maxWidth < constraints.maxHeight
? constraints.maxWidth
: constraints.maxHeight;
this.size = constraints.constrain(Size(size, size));
}
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
final center = Offset(size.width / 2, size.height / 2);
final radius = (size.width - _strokeWidth) / 2;
final bgPaint = Paint()
..color = _backgroundColor
..style = PaintingStyle.stroke
..strokeWidth = _strokeWidth
..strokeCap = StrokeCap.round;
canvas.drawCircle(center + offset, radius, bgPaint);
final fgPaint = Paint()
..color = _foregroundColor
..style = PaintingStyle.stroke
..strokeWidth = _strokeWidth
..strokeCap = StrokeCap.round;
canvas.drawArc(
Rect.fromCircle(center: center + offset, radius: radius),
-pi / 2,
2 * pi * _progress,
false,
fgPaint,
);
}
@override
bool hitTestSelf(Offset position) {
final center = Offset(size.width / 2, size.height / 2);
return (position - center).distance <= size.width / 2;
}
}
// 配套的 LeafRenderObjectWidget
class CircularProgressWidget extends LeafRenderObjectWidget {
final double progress;
final Color color;
final double strokeWidth;
const CircularProgressWidget({
super.key,
required this.progress,
required this.color,
this.strokeWidth = 8,
});
@override
RenderBox createRenderObject(BuildContext context) {
return CircularProgressRenderBox(
progress: progress,
foregroundColor: color,
strokeWidth: strokeWidth,
);
}
@override
void updateRenderObject(BuildContext context, CircularProgressRenderBox renderObject) {
renderObject
..progress = progress
..strokeWidth = strokeWidth;
}
}
三、PaintingContext 高级用法
dart
@override
void paint(PaintingContext context, Offset offset) {
// 裁剪画布(生成新 Layer)
context.pushClipRect(
needsCompositing,
offset,
Rect.fromLTWH(0, 0, size.width, size.height),
(context, offset) {
child?.paint(context, offset);
},
);
// 变换
context.pushTransform(
needsCompositing,
offset,
Matrix4.rotationZ(0.1),
(ctx, offset) => child?.paint(ctx, offset),
);
// 透明度
context.pushOpacity(offset, 128, (ctx, offset) {
child?.paint(ctx, offset);
});
}
四、绘制优化原则
dart
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
// ✅ 保存/恢复 Canvas 状态
canvas.save();
canvas.translate(offset.dx, offset.dy);
_paintContent(canvas);
canvas.restore();
}
// ✅ 缓存复杂的 Paint 对象(避免频繁创建)
final _borderPaint = Paint()
..color = Colors.blue
..style = PaintingStyle.stroke
..strokeWidth = 2;
// ✅ 仅在需要时才 markNeedsPaint / markNeedsLayout
set highlighted(bool value) {
if (_highlighted == value) return;
_highlighted = value;
markNeedsPaint();
}
小结
| 概念 | 要点 |
|---|---|
| RenderBox | 自定义布局+绘制,最大性能灵活度 |
| performLayout() | 计算 size,设置子节点 parentData |
| paint() | 在 Canvas 上绘制 |
| markNeedsPaint() | 只需重绘(不影响布局) |
| markNeedsLayout() | 需要重新布局(影响尺寸) |
| updateRenderObject() | Widget 更新时,增量更新 RenderObject 属性 |
11.4 Flutter 动画与物理模拟系统
Flutter 的动画系统不仅支持基于时间的缓动动画,还内置了弹簧、摩擦力等物理模拟,让动画效果更自然、真实。
一、动画系统架构
AnimationController(驱动器:产生 0.0~1.0 的值)
↓
Tween(映射器:将 0~1 映射到具体值范围)
↓
CurvedAnimation(缓动:应用非线性曲线)
↓
Animation<T>(最终动画值:T = double/Color/Offset/...)
↓
AnimatedBuilder / AnimatedWidget(监听并重建 Widget)
二、Simulation(物理模拟)
2.1 SpringSimulation(弹簧动画)
dart
class _SpringAnimationDemoState extends State<SpringAnimationDemo>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController.unbounded(vsync: this);
_startSpring(to: 200);
}
void _startSpring({required double to}) {
final spring = SpringDescription(
mass: 1.0, // 质量
stiffness: 200.0, // 刚度(越大越硬)
damping: 15.0, // 阻尼(越大越快停止)
);
final simulation = SpringSimulation(
spring,
_controller.value,
to,
0.0, // 初始速度
);
_controller.animateWith(simulation);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _startSpring(to: _controller.value == 200 ? 50 : 200),
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) => Stack(
children: [
Positioned(
top: _controller.value,
left: 100,
child: child!,
),
],
),
child: Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
2.2 FrictionSimulation(摩擦力动画)
dart
// 模拟抛出后减速停止(如列表滑动惯性)
void _throwWithFriction(double velocity) {
final simulation = FrictionSimulation(
0.1, // 摩擦系数
_controller.value, // 起始位置
velocity, // 初始速度
);
_controller.animateWith(simulation);
}
2.3 GravitySimulation(重力模拟)
dart
final simulation = GravitySimulation(
9.8 * 100, // 重力加速度(像素/s²)
0, // 起始位置
500, // 最大位置(落地点)
0, // 初始速度
);
_controller.animateWith(simulation);
三、多动画协调(Staggered Animation)
dart
class _StaggeredListAnimationState extends State<StaggeredListAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late List<Animation<Offset>> _slideAnimations;
late List<Animation<double>> _fadeAnimations;
static const int itemCount = 5;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
// 每个列表项错开 200ms 开始动画
_slideAnimations = List.generate(itemCount, (i) {
return Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _controller,
curve: Interval(
i * 0.15,
i * 0.15 + 0.5,
curve: Curves.easeOut,
),
));
});
_fadeAnimations = List.generate(itemCount, (i) {
return Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
parent: _controller,
curve: Interval(i * 0.15, i * 0.15 + 0.4),
));
});
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, _) {
return Column(
children: List.generate(itemCount, (i) {
return FadeTransition(
opacity: _fadeAnimations[i],
child: SlideTransition(
position: _slideAnimations[i],
child: ListTile(title: Text('Item ${i + 1}')),
),
);
}),
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
四、拖拽 + 弹簧回弹
dart
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
Offset _dragOffset = Offset.zero;
@override
void initState() {
super.initState();
_controller = AnimationController.unbounded(vsync: this);
}
void _onPanEnd(DragEndDetails details) {
final spring = SpringDescription(mass: 1, stiffness: 300, damping: 20);
_controller.animateWith(SpringSimulation(spring, _dragOffset.dx, 0, 0));
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: (details) {
setState(() => _dragOffset += details.delta);
},
onPanEnd: _onPanEnd,
child: Transform.translate(
offset: _dragOffset,
child: const Card(child: Padding(padding: EdgeInsets.all(16), child: Text('拖拽我'))),
),
);
}
}
小结
| 类型 | 适用场景 |
|---|---|
| Tween + Curves | 固定时长的属性动画 |
| SpringSimulation | 弹性回弹、自然感交互 |
| FrictionSimulation | 惯性滚动、抛出效果 |
| GravitySimulation | 重力下落效果 |
| Interval + Stagger | 列表项错开入场动画 |
11.5 高级主题:Isolate 与 FFI
Isolate 和 FFI 是 Flutter/Dart 的两个高级能力:Isolate 实现真正的多线程计算,FFI 则允许 Dart 直接调用 C 语言库。
一、Isolate 与计算
1.1 compute()(简单后台计算)
dart
// 顶层函数(必须可序列化)
List<Product> parseProducts(String jsonString) {
final list = jsonDecode(jsonString) as List;
return list.map((e) => Product.fromJson(e)).toList();
}
// 在主线程调用,但在 Isolate 中执行
Future<void> loadProducts() async {
final jsonString = await fetchProductsJson();
// 解析 JSON 在独立 Isolate 中执行,不阻塞 UI
final products = await compute(parseProducts, jsonString);
setState(() => _products = products);
}
限制:
- 函数必须是顶层函数或 static 方法
- 参数和返回值必须可以跨 Isolate 传递(基本类型、List、Map)
1.2 Isolate.spawn(长期后台任务)
dart
class ImageProcessingService {
static Isolate? _isolate;
static SendPort? _sendPort;
static final ReceivePort _receivePort = ReceivePort();
static Future<void> initialize() async {
_isolate = await Isolate.spawn(
_isolateEntry,
_receivePort.sendPort,
);
_sendPort = await _receivePort.first;
}
static Future<Uint8List> processImage(Uint8List imageData) async {
final responsePort = ReceivePort();
_sendPort!.send([responsePort.sendPort, imageData]);
return await responsePort.first;
}
static void _isolateEntry(SendPort mainSendPort) {
final receivePort = ReceivePort();
mainSendPort.send(receivePort.sendPort);
receivePort.listen((message) {
final responseSendPort = message[0] as SendPort;
final imageData = message[1] as Uint8List;
final processed = _applyFilter(imageData);
responseSendPort.send(processed);
});
}
static Uint8List _applyFilter(Uint8List data) => data;
static void dispose() {
_isolate?.kill();
_receivePort.close();
}
}
1.3 Isolate.run(Dart 2.19+,最简单)
dart
final result = await Isolate.run(() {
return _performHeavyComputation(data);
});
二、FFI(Foreign Function Interface)
dart:ffi 允许 Dart 直接调用 C/C++ 的原生库,无需 Platform Channel,性能更高。
2.1 基本示例
c
// native/math.c
#include <stdint.h>
int64_t add(int64_t a, int64_t b) {
return a + b;
}
double calculate_pi(int iterations) {
double pi = 0;
for (int i = 0; i < iterations; i++) {
pi += (i % 2 == 0 ? 1 : -1) * (1.0 / (2 * i + 1));
}
return pi * 4;
}
dart
// lib/native_math.dart
import 'dart:ffi';
import 'dart:io';
typedef AddFunc = Int64 Function(Int64 a, Int64 b);
typedef AddDart = int Function(int a, int b);
typedef CalcPiFunc = Double Function(Int32 iterations);
typedef CalcPiDart = double Function(int iterations);
class NativeMath {
static late DynamicLibrary _lib;
static late AddDart add;
static late CalcPiDart calculatePi;
static void initialize() {
_lib = Platform.isAndroid
? DynamicLibrary.open('libnative_math.so')
: DynamicLibrary.process();
add = _lib.lookupFunction<AddFunc, AddDart>('add');
calculatePi = _lib.lookupFunction<CalcPiFunc, CalcPiDart>('calculate_pi');
}
}
// 使用
NativeMath.initialize();
print(NativeMath.add(1, 2)); // 3
print(NativeMath.calculatePi(1000000)); // 3.1415...
2.2 结构体(Struct)
dart
final class Point extends Struct {
@Double()
external double x;
@Double()
external double y;
}
typedef DistanceFunc = Double Function(Pointer<Point>, Pointer<Point>);
typedef DistanceDart = double Function(Pointer<Point>, Pointer<Point>);
final distanceFn = _lib.lookupFunction<DistanceFunc, DistanceDart>('distance');
final pointA = calloc<Point>()
..ref.x = 0
..ref.y = 0;
final pointB = calloc<Point>()
..ref.x = 3
..ref.y = 4;
final d = distanceFn(pointA, pointB); // 5.0
calloc.free(pointA);
calloc.free(pointB);
2.3 FFI 常用类型映射
| C 类型 | Dart FFI 类型 | Dart 原生类型 |
|---|---|---|
int32_t |
Int32 |
int |
int64_t |
Int64 |
int |
double |
Double |
double |
float |
Float |
double |
bool |
Bool |
bool |
char* |
Pointer<Char> |
需转换 |
struct |
extends Struct |
- |
小结
| 技术 | 适用场景 | 难度 |
|---|---|---|
compute() |
简单的一次性后台计算 | ⭐ |
Isolate.run() |
简洁的一次性 Isolate | ⭐ |
Isolate.spawn() |
长期后台任务,持续通信 | ⭐⭐⭐ |
dart:ffi |
调用 C/C++ 库,极致性能 | ⭐⭐⭐⭐ |
11.6 Dart 并发编程进阶
Dart 是单线程的,但提供了 async/await、Isolate、Zone 等机制实现异步和并行。深入理解这些原语,是解决性能瓶颈和复杂并发问题的关键。
一、事件循环(Event Loop)
Dart 运行时内部:
┌─────────────────────────────────────┐
│ Microtask Queue │ ← 高优先级:scheduleMicrotask()、Future.microtask()
├─────────────────────────────────────┤
│ Event Queue │ ← 普通优先级:I/O、Timer、Stream 事件
└─────────────────────────────────────┘
处理顺序:
1. 执行当前同步代码
2. 清空 Microtask Queue(全部)
3. 取出一个 Event Queue 事件处理
4. 重复 2-3
dart
void main() {
print('1 - 同步');
Future(() => print('4 - Event Queue(Future)'));
Future.microtask(() => print('3 - Microtask Queue'));
scheduleMicrotask(() => print('2 - Microtask Queue(scheduleMicrotask)'));
print('1.5 - 同步');
}
// 输出顺序:1 → 1.5 → 2 → 3 → 4
二、Future 链式操作
dart
Future<UserProfile> loadProfile(int userId) {
return fetchUser(userId)
.then((user) => fetchProfilePicture(user.avatarUrl))
.then((avatar) => UserProfile(user: user, avatar: avatar))
.catchError((e) {
debugPrint('加载失败: $e');
return UserProfile.empty();
})
.whenComplete(() => debugPrint('加载完成'));
}
// 并行执行多个 Future
Future<void> loadDashboard() async {
final results = await Future.wait([
fetchUserInfo(),
fetchOrders(),
fetchNotifications(),
fetchBanners(),
]);
}
// 竞速(取最快完成的)
final result = await Future.any([
fetchFromPrimaryServer(),
fetchFromBackupServer(),
]).timeout(
const Duration(seconds: 5),
onTimeout: () => throw TimeoutException('请求超时'),
);
三、Stream 进阶
dart
Stream<Order> processOrders(Stream<RawOrder> rawStream) {
return rawStream
.where((o) => o.status == 'pending') // 过滤
.map((o) => Order.fromRaw(o)) // 转换
.distinct() // 去重
.asyncMap((o) => enrichWithUserInfo(o)) // 异步变换
.timeout(const Duration(seconds: 10)) // 超时
.handleError((e) => debugPrint('流错误: $e')); // 错误处理
}
class OrderStreamService {
final _controller = StreamController<Order>.broadcast();
Stream<Order> get orderStream => _controller.stream;
void addOrder(Order order) {
if (!_controller.isClosed) {
_controller.add(order);
}
}
Future<void> dispose() => _controller.close();
}
// 使用 Stream 实现状态机
Stream<AppState> appStateStream() async* {
yield AppState.loading;
try {
final data = await fetchInitialData();
yield AppState.loaded(data);
} catch (e) {
yield AppState.error(e.toString());
}
}
四、Zone(错误隔离与埋点)
dart
import 'dart:async';
// 全局错误捕获
runZonedGuarded(
() {
runApp(const MyApp());
},
(error, stackTrace) {
ErrorReporter.report(error, stackTrace);
},
);
// 性能监控(拦截所有 Timer 调用)
final zone = Zone.current.fork(
specification: ZoneSpecification(
createTimer: (self, parent, zone, duration, callback) {
return parent.createTimer(zone, duration, () {
final sw = Stopwatch()..start();
callback();
debugPrint('Timer 回调耗时: ${sw.elapsedMilliseconds}ms');
});
},
),
);
zone.run(() {
Timer(Duration.zero, _heavyOperation);
});
五、Isolate 高级通信
dart
class BackgroundWorker {
Isolate? _isolate;
SendPort? _sendPort;
final _receivePort = ReceivePort();
final _pendingRequests = <int, Completer>{};
int _requestId = 0;
Future<void> start() async {
_isolate = await Isolate.spawn(_workerMain, _receivePort.sendPort);
await for (final message in _receivePort) {
if (message is SendPort) {
_sendPort = message;
break;
}
}
_receivePort.listen((message) {
if (message is Map && message.containsKey('id')) {
final id = message['id'] as int;
final completer = _pendingRequests.remove(id);
if (message.containsKey('error')) {
completer?.completeError(message['error']);
} else {
completer?.complete(message['result']);
}
}
});
}
Future<T> sendRequest<T>(String method, dynamic args) async {
final id = ++_requestId;
final completer = Completer<T>();
_pendingRequests[id] = completer;
_sendPort?.send({'id': id, 'method': method, 'args': args});
return completer.future;
}
static void _workerMain(SendPort mainSendPort) {
final receivePort = ReceivePort();
mainSendPort.send(receivePort.sendPort);
receivePort.listen((message) {
final id = message['id'] as int;
final method = message['method'] as String;
final args = message['args'];
try {
final result = _dispatchMethod(method, args);
mainSendPort.send({'id': id, 'result': result});
} catch (e) {
mainSendPort.send({'id': id, 'error': e.toString()});
}
});
}
static dynamic _dispatchMethod(String method, dynamic args) {
return switch (method) {
'hash' => _computeHash(args as String),
'compress' => _compress(args as List<int>),
_ => throw UnsupportedError('Unknown method: $method'),
};
}
static String _computeHash(String data) => '';
static List<int> _compress(List<int> data) => [];
void stop() {
_isolate?.kill(priority: Isolate.immediate);
_receivePort.close();
}
}
六、async/await 常见陷阱
dart
// ❌ 陷阱一:在循环中串行 await
for (final id in ids) {
await fetchItem(id); // 每个请求都要等上一个完成!
}
// ✅ 并行请求
await Future.wait(ids.map((id) => fetchItem(id)));
// ❌ 陷阱二:忘记 await Future 函数
void uploadFile() {
_doUpload(); // 没有 await,错误会被忽略!
}
// ✅
Future<void> uploadFile() async {
await _doUpload();
}
// ❌ 陷阱三:在 dispose 后 setState
Future<void> loadData() async {
final data = await fetch();
setState(() => _data = data); // Widget 已 dispose 会报错!
}
// ✅
Future<void> loadData() async {
final data = await fetch();
if (!mounted) return;
setState(() => _data = data);
}
// ❌ 陷阱四:Stream 未取消订阅导致内存泄漏
class _State extends State<MyWidget> {
late StreamSubscription _sub;
@override
void initState() {
super.initState();
_sub = someStream.listen((_) {});
}
@override
void dispose() {
_sub.cancel(); // ✅ 必须取消!
super.dispose();
}
}
小结
| 概念 | 要点 |
|---|---|
| Event Loop | Microtask 优先于 Event Queue |
| Future.wait | 并行执行,等所有完成 |
| Future.any | 取最快完成的(竞速) |
| Stream | where/map/asyncMap 链式变换 |
| Zone | 全局错误捕获、异步操作拦截 |
| Isolate 通信 | SendPort + ReceivePort 实现 RPC 模式 |
章节总结
| 知识点 | 必掌握程度 |
|---|---|
| Layer Tree / Skia 渲染原理 | ⭐⭐⭐⭐ |
| JIT vs AOT 编译机制 | ⭐⭐⭐⭐⭐ |
| Tree Shaking | ⭐⭐⭐⭐ |
| 自定义 RenderObject | ⭐⭐⭐ |
| 物理动画(Spring/Friction) | ⭐⭐⭐⭐ |
| compute / Isolate.spawn | ⭐⭐⭐⭐⭐ |
| dart:ffi | ⭐⭐⭐ |
| Event Loop / Future / Stream | ⭐⭐⭐⭐⭐ |
👉 下一章:第十二章------实战项目与最佳实践