Flutter 的异常处理机制包括 同步异常 和 异步异常 ,涉及多个层面,如 Dart 语言级别的异常捕获 、Flutter 框架的错误处理机制 、自定义异常处理 以及 错误上报。
1. Dart 语言级别的异常处理
Dart 主要使用 try-catch
进行异常捕获,并区分 同步异常 和 异步异常 的处理方式。
1.1. 同步异常
同步代码中的异常可以通过 try-catch
捕获:
php
dart
复制编辑
void main() {
try {
int result = 10 ~/ 0; // 除以 0,会触发异常
} catch (e, stackTrace) {
print("捕获异常: $e");
print("堆栈信息: $stackTrace");
}
}
e
捕获异常对象stackTrace
获取异常发生的堆栈信息,方便调试
常见异常类型:
FormatException
:数据格式错误RangeError
:数组越界TypeError
:类型转换错误StateError
:非法状态操作ArgumentError
:参数错误
1.2. 异步异常
Flutter 使用 异步编程(Future 和 Stream) ,因此要特别注意 Future
和 Stream
的异常处理。
1.2.1. Future 异常处理
异步 Future
任务的异常需要使用 .catchError()
或 try-catch
捕获:
csharp
dart
复制编辑
Future<void> asyncTask() async {
try {
await Future.delayed(Duration(seconds: 1));
throw Exception("异步任务异常");
} catch (e) {
print("捕获 Future 异常: $e");
}
}
void main() {
asyncTask();
}
另一种方式是 .catchError()
:
javascript
dart
复制编辑
Future<void> asyncTask() {
return Future.delayed(Duration(seconds: 1))
.then((_) => throw Exception("异步任务异常"))
.catchError((e) {
print("Future 捕获异常: $e");
});
}
1.2.2. Stream 异常处理
Stream
中的异常不会自动抛出,需要使用 handleError()
或 try-catch
捕获:
dart
dart
复制编辑
void main() {
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (count) {
if (count == 2) throw Exception("Stream 发生错误");
return count;
}).take(5);
stream.listen(
(data) => print("收到数据: $data"),
onError: (error) => print("捕获 Stream 异常: $error"),
);
}
2. Flutter 框架级别的异常处理
Flutter 提供了一套全局异常处理机制,包括:
FlutterError.onError
PlatformDispatcher.instance.onError
runZonedGuarded
2.1. 处理 Flutter 框架错误 (FlutterError.onError
)
Flutter 框架内部的异常(例如 setState()
期间的异常)会由 FlutterError.onError
处理:
scss
dart
复制编辑
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
print("Flutter 框架错误: ${details.exception}");
print("错误详情: ${details.stack}");
};
runApp(MyApp());
}
应用场景
- 捕获 UI 相关异常,如
build()
方法中的错误 - 处理 Flutter 框架错误
2.2. 捕获 Native 层异常 (PlatformDispatcher.instance.onError
)
PlatformDispatcher.instance.onError
可用于捕获 Flutter Engine 层的异常:
arduino
dart
复制编辑
void main() {
PlatformDispatcher.instance.onError = (error, stack) {
print("捕获 Native 层异常: $error");
return true; // 阻止异常冒泡
};
runApp(MyApp());
}
适用场景
- 处理 Dart 代码未捕获的异常
- 监听 Native 层的异常信息
2.3. 捕获 runZonedGuarded
异常
Dart 允许在 runZonedGuarded
中执行代码,确保 Future
或 Stream
中的异常不会导致程序崩溃:
scss
dart
复制编辑
void main() {
runZonedGuarded(() {
runApp(MyApp());
}, (error, stackTrace) {
print("runZonedGuarded 捕获到异常: $error");
});
}
适用场景
- 全局捕获 Future 异常
- 防止异常导致 App 崩溃
- 统一上报异常
3. 统一异常上报
在生产环境中,异常通常需要上报到日志系统(如 Sentry、Firebase Crashlytics)。
3.1. 结合 FlutterError.onError
进行上报
scss
dart
复制编辑
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
// 发送错误信息到服务器
reportError(details.exception, details.stack);
};
runApp(MyApp());
}
void reportError(Object error, StackTrace? stack) {
// 发送到 Sentry 或 Firebase
print("上报错误: $error");
}
4. Widget 层面的异常捕获
有时,我们希望在 UI 层面防止崩溃,比如 build()
发生异常时显示默认 UI。
4.1. 使用 ErrorWidget
Flutter 允许替换 ErrorWidget
,在 Widget
构建失败时显示自定义错误页面:
scss
dart
复制编辑
void main() {
ErrorWidget.builder = (FlutterErrorDetails details) {
return Center(child: Text("发生错误: ${details.exceptionAsString()}"));
};
runApp(MyApp());
}
5. 总结
机制 | 作用 | 适用场景 |
---|---|---|
try-catch |
捕获同步异常 | 同步代码异常 |
catchError() |
处理 Future 异常 | 异步异常 |
handleError() |
处理 Stream 异常 | Stream 发生错误 |
FlutterError.onError |
捕获 Flutter 框架错误 | Widget build() 失败 |
PlatformDispatcher.instance.onError |
监听 Engine 级错误 | Flutter Engine 发生崩溃 |
runZonedGuarded |
保护全局异步代码 | 防止 Future 未捕获异常导致崩溃 |
ErrorWidget.builder |
自定义 UI 错误页面 | Widget 级别错误 |
6. 最佳实践
- 对所有 Future 代码使用
catchError()
- 对所有 Stream 监听使用
handleError()
- 使用
FlutterError.onError
统一收集 UI 相关异常 - 使用
runZonedGuarded
防止未捕获的异步异常 - 上报错误到日志服务(Sentry、Firebase Crashlytics)
- 自定义
ErrorWidget.builder
让 UI 崩溃可视化 PlatformDispatcher.instance.onError
监听 Native 层错误
Flutter 的异常处理涉及多个层面,从 Dart 语言层、Flutter 框架层到 UI 组件层,掌握这些机制能有效提升 App 的稳定性,减少崩溃情况。