Flutter 中的錯誤處理
如何控制錯誤訊息和錯誤日誌記錄
Flutter 框架會捕獲在框架自身觸發的回撥期間發生的錯誤,包括在構建、佈局和繪製階段遇到的錯誤。那些不在 Flutter 回撥中發生的錯誤無法被框架捕獲,但你可以透過在 PlatformDispatcher 上設定錯誤處理程式來處理它們。
Flutter 捕獲的所有錯誤都會路由到 FlutterError.onError 處理程式。預設情況下,這會呼叫 FlutterError.presentError,後者將錯誤轉儲到裝置日誌中。在 IDE 中執行時,檢查器會覆蓋此行為,以便錯誤也可以路由到 IDE 的控制檯,從而讓你檢查訊息中提到的物件。
當錯誤在構建階段發生時,會呼叫 ErrorWidget.builder 回撥來構建用於替換失敗小部件的小部件。預設情況下,在除錯模式下,這會在紅色中顯示錯誤訊息,而在釋出模式下,這會顯示灰色背景。
當錯誤在沒有 Flutter 回撥在呼叫堆疊上時發生時,它們由 PlatformDispatcher 的錯誤回撥處理。預設情況下,這隻會列印錯誤,而不會執行任何其他操作。
你可以自定義這些行為,通常透過在你的 void main() 函式中將它們設定為值。
下面將解釋每種錯誤型別處理方式。在底部有一個程式碼片段,可以處理所有型別的錯誤。雖然你可以直接複製-貼上該片段,但我們建議你先了解每種錯誤型別。
Flutter 捕獲的錯誤
#例如,要使你的應用程式在釋出模式下捕獲到 Flutter 的任何錯誤時立即退出,你可以使用以下處理程式
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
FlutterError.onError = (details) {
FlutterError.presentError(details);
if (kReleaseMode) exit(1);
};
runApp(const MyApp());
}
// The rest of the `flutter create` code...
此處理程式也可以用於將錯誤報告給日誌記錄服務。有關更多詳細資訊,請參閱我們的食譜章節,瞭解 將錯誤報告給服務。
為構建階段錯誤定義自定義錯誤小部件
#要定義一個自定義錯誤小部件,該小部件會在構建器構建小部件失敗時顯示,請使用 MaterialApp.builder。
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, widget) {
Widget error = const Text('...rendering error...');
if (widget is Scaffold || widget is Navigator) {
error = Scaffold(body: Center(child: error));
}
ErrorWidget.builder = (errorDetails) => error;
if (widget != null) return widget;
throw StateError('widget is null');
},
);
}
}
Flutter 未捕獲的錯誤
#考慮一個 onPressed 回撥,它呼叫一個非同步函式,例如 MethodChannel.invokeMethod(或幾乎任何外掛)。例如
OutlinedButton(
child: const Text('Click me!'),
onPressed: () async {
const channel = MethodChannel('crashy-custom-channel');
await channel.invokeMethod('blah');
},
)
如果 invokeMethod 丟擲錯誤,它不會轉發到 FlutterError.onError。相反,它會轉發到 PlatformDispatcher。
要捕獲此類錯誤,請使用 PlatformDispatcher.instance.onError。
import 'package:flutter/material.dart';
import 'dart:ui';
void main() {
MyBackend myBackend = MyBackend();
PlatformDispatcher.instance.onError = (error, stack) {
myBackend.sendError(error, stack);
return true;
};
runApp(const MyApp());
}
處理所有型別的錯誤
#假設你想在任何異常發生時退出應用程式,並在小部件構建失敗時顯示自定義錯誤小部件 - 你可以基於以下程式碼片段來處理你的錯誤
import 'package:flutter/material.dart';
import 'dart:ui';
Future<void> main() async {
await myErrorsHandler.initialize();
FlutterError.onError = (details) {
FlutterError.presentError(details);
myErrorsHandler.onErrorDetails(details);
};
PlatformDispatcher.instance.onError = (error, stack) {
myErrorsHandler.onError(error, stack);
return true;
};
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, widget) {
Widget error = const Text('...rendering error...');
if (widget is Scaffold || widget is Navigator) {
error = Scaffold(body: Center(child: error));
}
ErrorWidget.builder = (errorDetails) => error;
if (widget != null) return widget;
throw StateError('widget is null');
},
);
}
}