😋 初始化仓库
This commit is contained in:
174
lib/utils/error_handler.dart
Normal file
174
lib/utils/error_handler.dart
Normal file
@@ -0,0 +1,174 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_logger.dart';
|
||||
import 'exceptions.dart';
|
||||
|
||||
/// Global error handler for the application
|
||||
class ErrorHandler {
|
||||
static final ErrorHandler _instance = ErrorHandler._internal();
|
||||
factory ErrorHandler() => _instance;
|
||||
ErrorHandler._internal();
|
||||
|
||||
final AppLogger _logger = AppLogger();
|
||||
bool _isInitialized = false;
|
||||
|
||||
/// Initialize global error handling
|
||||
void initialize() {
|
||||
if (_isInitialized) return;
|
||||
|
||||
// Capture Flutter framework errors
|
||||
FlutterError.onError = (FlutterErrorDetails details) {
|
||||
_handleFlutterError(details);
|
||||
};
|
||||
|
||||
// Capture errors in platform-specific code
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
_handlePlatformError(error, stack);
|
||||
return true;
|
||||
};
|
||||
|
||||
_isInitialized = true;
|
||||
_logger.info('Global error handler initialized');
|
||||
}
|
||||
|
||||
/// Run the app with error zone guarding
|
||||
static Future<void> runAppWithErrorHandling(
|
||||
Future<void> Function() appRunner,
|
||||
) async {
|
||||
final errorHandler = ErrorHandler();
|
||||
errorHandler.initialize();
|
||||
|
||||
// Run app in a guarded zone to catch async errors
|
||||
await runZonedGuarded(
|
||||
() async {
|
||||
await appRunner();
|
||||
},
|
||||
(error, stackTrace) {
|
||||
errorHandler._handleZoneError(error, stackTrace);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle Flutter framework errors
|
||||
void _handleFlutterError(FlutterErrorDetails details) {
|
||||
// Log the error
|
||||
_logger.error(
|
||||
'Flutter Error',
|
||||
error: details.exception,
|
||||
stackTrace: details.stack,
|
||||
);
|
||||
|
||||
// In debug mode, show the red error screen
|
||||
if (kDebugMode) {
|
||||
FlutterError.presentError(details);
|
||||
}
|
||||
|
||||
// Optionally report to crash reporting service
|
||||
_reportError(details.exception, details.stack);
|
||||
}
|
||||
|
||||
/// Handle platform-specific errors
|
||||
bool _handlePlatformError(Object error, StackTrace stackTrace) {
|
||||
_logger.error('Platform Error', error: error, stackTrace: stackTrace);
|
||||
|
||||
_reportError(error, stackTrace);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Handle errors from runZonedGuarded
|
||||
void _handleZoneError(Object error, StackTrace stackTrace) {
|
||||
_logger.error('Async Error', error: error, stackTrace: stackTrace);
|
||||
|
||||
_reportError(error, stackTrace);
|
||||
}
|
||||
|
||||
/// Report error to external service (optional)
|
||||
void _reportError(Object error, StackTrace? stackTrace) {
|
||||
// In production, you could send errors to services like:
|
||||
// - Firebase Crashlytics
|
||||
// - Sentry
|
||||
// - Custom error reporting endpoint
|
||||
|
||||
if (kReleaseMode) {
|
||||
// TODO: Implement error reporting to external service
|
||||
// Example: FirebaseCrashlytics.instance.recordError(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle and display user-friendly error messages
|
||||
static String getUserFriendlyMessage(Object error) {
|
||||
if (error is AppException) {
|
||||
return error.message;
|
||||
} else if (error is NetworkException) {
|
||||
return '网络连接失败,请检查网络设置';
|
||||
} else if (error is AuthenticationException) {
|
||||
return '登录失败,请检查账号密码';
|
||||
} else if (error is ParseException) {
|
||||
return '数据解析失败,请稍后重试';
|
||||
} else if (error is ValidationException) {
|
||||
return '输入验证失败:${error.message}';
|
||||
} else if (error is TimeoutException) {
|
||||
return '请求超时,请稍后重试';
|
||||
} else if (error is FormatException) {
|
||||
return '数据格式错误';
|
||||
} else {
|
||||
return '发生未知错误,请稍后重试';
|
||||
}
|
||||
}
|
||||
|
||||
/// Show error dialog to user
|
||||
static void showErrorDialog(
|
||||
BuildContext context,
|
||||
Object error, {
|
||||
VoidCallback? onRetry,
|
||||
}) {
|
||||
final message = getUserFriendlyMessage(error);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('错误'),
|
||||
content: Text(message),
|
||||
actions: [
|
||||
if (onRetry != null)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onRetry();
|
||||
},
|
||||
child: const Text('重试'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Show error snackbar to user
|
||||
static void showErrorSnackBar(
|
||||
BuildContext context,
|
||||
Object error, {
|
||||
Duration duration = const Duration(seconds: 3),
|
||||
}) {
|
||||
final message = getUserFriendlyMessage(error);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
duration: duration,
|
||||
backgroundColor: Colors.red,
|
||||
action: SnackBarAction(
|
||||
label: '关闭',
|
||||
textColor: Colors.white,
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user