flutter: 捕捉异常:处理Widget构建时的错误
一,代码:
1,main
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'services/AuthService.dart';
import 'routes/routes.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
void main() {
runZonedGuarded(() {
// 第二层:Flutter框架自身的错误回调
FlutterError.onError = (FlutterErrorDetails details) {
print("捕捉到了异常");
FlutterError.presentError(details); // 开发时显示红屏
print('详情打印开始:');
String detail = details.toString();
print(detail);
print('详情打印结束:');
};
// 第三层:Widget构建时的错误边界
ErrorWidget.builder = (FlutterErrorDetails details) {
// 当Widget构建失败时,展示我们自定义的错误界面,而不是崩溃
print('Widget错误时详情打印开始:');
String detail = details.toString();
print(detail);
print('Widget错误时详情打印结束:');
return ErrorRecoveryWidget(details);
};
runApp(MyApp());
}, (error, stackTrace) {
// 处理所有未被前面捕获的异常
//_handleZoneError(error, stackTrace);
//print("处理所有未被前面捕获的异常");
//print(error);
print('未被前面捕获的异常: $error');
print('未被前面捕获的异常的堆栈: $stackTrace');
});
}
class ErrorRecoveryWidget extends StatelessWidget {
final FlutterErrorDetails errorDetails;
final VoidCallback? onRetry;
const ErrorRecoveryWidget(
this.errorDetails, {
this.onRetry,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
child: Container(
color: Colors.grey[100],
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
size: 64,
color: Colors.red[400],
),
const SizedBox(height: 20),
Text(
'页面加载失败',
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: Colors.red[700],
),
),
const SizedBox(height: 12),
Text(
errorDetails.exceptionAsString(),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.grey),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 24),
if (onRetry != null)
ElevatedButton.icon(
onPressed: onRetry,
icon: const Icon(Icons.refresh),
label: const Text('重试'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 16),
TextButton(
onPressed: () {
showErrorDetailsDialog(context, errorDetails);
},
child: const Text('查看错误详情'),
),
],
),
),
);
}
// 提供一个对话框展示详细的错误信息,方便调试
void showErrorDetailsDialog(BuildContext context, FlutterErrorDetails details) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('错误详情'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('异常类型:', style: TextStyle(fontWeight: FontWeight.bold)),
SelectableText(details.exception.runtimeType.toString()),
const SizedBox(height: 12),
const Text('异常信息:', style: TextStyle(fontWeight: FontWeight.bold)),
SelectableText(details.exception.toString()),
const SizedBox(height: 12),
const Text('堆栈跟踪:', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(
height: 200,
child: SingleChildScrollView(
child: SelectableText(details.stack.toString()),
),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('关闭'),
),
TextButton(
onPressed: () {
Clipboard.setData(ClipboardData(
text: '${details.exception}\n\n${details.stack}'
));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已复制到剪贴板')),
);
},
child: const Text('复制'),
),
],
),
);
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(750, 1334),
minTextAdapt: true,
splitScreenMode: true,
// Use builder only if you need to use library outside ScreenUtilInit context
builder: (_ , child) {
return GetMaterialApp(
debugShowCheckedModeBanner: false, //去除debug图标
defaultTransition: Transition.rightToLeft, //指定动画
theme: ThemeData(primarySwatch: Colors.red),
initialRoute: "/", //初始化页面
getPages: APPage.routes, //路由
);
},
);
}
}
2,homepage
用来触发异常:
在这里,我们犯了一个明显的错误,在我们知道的 null 小部件上使用了 bang 运算符(!),
这导致在非发布模式下出现红屏,在发布模式下出现灰屏。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
const widget = null;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text("home页面"),
),
body:widget!
);
}
}
二,测试效果:


浙公网安备 33010602011771号