全局ref="/tag/153/" style="color:#8B0506;font-weight:bold;">异常捕获:让崩溃无处可藏
在开发Flutter应用时,难免会遇到运行时异常。比如用户操作过快导致状态未初始化,或者网络请求返回了意料之外的数据结构。这些异常如果不处理,轻则页面白屏,重则直接闪退。这时候,全局异常捕获就显得尤为重要。
Flutter提供了FlutterError.onError和PlatformDispatcher.instance.onError两个入口来监听异常。前者负责捕获框架层的错误,后者则能捕获 Dart 层未处理的异常。
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.dumpErrorToConsole(details);
logException(details); // 自定义上报逻辑
};
PlatformDispatcher.instance.onError = (Object error, StackTrace stack) {
logException(error, stack);
return true;
};
runApp(MyApp());
};这样设置后,哪怕某个页面因为空指针触发了异常,也能被拦截下来,而不是让用户看到一个灰白的崩溃界面。
局部异常处理:精准控制出错边界
有些场景下,并不需要全局兜底。比如加载用户头像时图片链接失效,这种错误可以局部消化掉,用默认图代替即可。这时候可以用try/catch配合异步操作。
Future<void> loadUserProfile() async {
try {
final response = await http.get(Uri.parse(userApi));
if (response.statusCode == 200) {
setState({});
}
} catch (e, s) {
reportToAnalytics('profile_load_failed', e, s);
useDefaultAvatar();
}
}这种方式适合已知可能出错且能降级处理的场景,避免把小问题升级成整个应用的崩溃。
Widget层级的错误拦截
有时候某个组件内部出错,但不希望影响父组件的渲染。比如评论区里一条数据格式异常,不应该导致整个列表无法显示。这时可以用ErrorWidget.builder自定义错误展示内容。
ErrorWidget.builder = (FlutterErrorDetails details) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16),
child: Text(
'内容加载异常',
style: TextStyle(color: Colors.grey),
),
);
};也可以结合addPostFrameCallback在帧绘制完成后监控异常,用于记录哪些页面更容易出现UI构建失败。
异常上报与日志分析
捕获到异常只是第一步,关键是要能快速定位问题。可以把异常信息加上设备型号、系统版本、网络状态等上下文打包发送到监控平台。例如使用Sentry或自建日志服务。
void logException(Object error, [StackTrace? stack]) {
final Map<String, String> metadata = {
'device': getDeviceModel(),
'os_version': getOSVersion(),
'app_version': getAppVersion(),
};
Analytics.reportError(error, stack, metadata);
}上线后发现某安卓机型频繁报RenderBox was not laid out,通过上报日志查到是特定屏幕尺寸下布局计算溢出,修复后崩溃率明显下降。