在 Flutter 裡處理錯誤
Flutter 框架可以捕獲執行期間的錯誤,包括建構期間、佈局期間和繪製期間。
所有 Flutter 的錯誤均會被回呼(Callback)方法 FlutterError.onError
捕獲。預設情況下,會呼叫 FlutterError.presentError
方法,並將錯誤轉儲到當前的裝置日誌中。當從 IDE 執行應用時,檢查器重寫了該方法,錯誤也被髮送到 IDE 的控制檯,可以在控制檯中檢查出錯的物件。
當建構期間發生錯誤時,回呼(Callback)函式 ErrorWidget.builder
會被呼叫,來產生一個新的 widget,用來代替建構失敗的 widget。預設情況,debug 模式下會顯示一個紅色背景的錯誤頁面,
release 模式下會展示一個灰色背景的空白頁面。
如果在呼叫堆疊上沒有 Flutter 回呼(Callback)的情況下發生錯誤,它們由發生區域的 Zone
處理。
Zone
在預設情況下僅會列印錯誤,而不會執行其他任何操作。
這些回呼(Callback)方法都可以被重寫,通常在 void main()
方法中重寫。
下面解釋了所有的錯誤捕獲型別。在最後的程式碼段可以用於處理所有型別的錯誤。儘管你可以直接複製貼上程式碼段,但我們建議你先了解每種錯誤型別。
Flutter 導致的錯誤
例如,如果你想在 release 模式下發生錯誤時立刻關閉應用,可以使用下面的回呼(Callback)方法:
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());
}
// rest of `flutter create` code...
這個回呼(Callback)方法也可以上報錯誤到日誌服務平台。更多資訊可以檢視文件 報錯資訊透過服務上傳。
自訂一個 ErrorWidget 以展示 build 時的錯誤
定義一個自訂的 error widget,以當 builder 建構 widget 失敗時顯示,請使用 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 ('widget is null');
},
);
}
}
未被 Flutter 捕獲的錯誤
假設一個 onPressed
回呼(Callback)呼叫了非同步方法,例如 MethodChannel.invokeMethod
(或者其他 plugin 的方法):
OutlinedButton(
child: const Text('Click me!'),
onPressed: () async {
const channel = MethodChannel('crashy-custom-channel')
await channel.invokeMethod('blah')
},
)
如果 invokeMethod
丟擲了錯誤,它不會傳遞至 FlutterError.onError
,而是直接進入 runApp
的 Zone
。
如果你想捕獲這樣的錯誤,請使用 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());
}
處理所有型別的錯誤
如果你想在例外丟擲時退出應用,並在 build 錯誤時展示自訂的 ErrorWidget,你可以在下面的程式碼片段的基礎上客製你的處理:
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 ('widget is null');
},
);
}
}