跳到主內容

在 Flutter 中處理錯誤

如何控制錯誤訊息和錯誤日誌記錄

Flutter 框架會捕獲由框架本身觸發的回撥期間發生的錯誤,包括在構建 (build)、佈局 (layout) 和繪製 (paint) 階段遇到的錯誤。未在 Flutter 回撥內發生的錯誤無法被框架捕獲,但你可以透過在 PlatformDispatcher 上設定錯誤處理器來處理它們。

所有由 Flutter 捕獲的錯誤都會被路由到 FlutterError.onError 處理器。預設情況下,它會呼叫 FlutterError.presentError,將錯誤轉儲到裝置日誌中。當從 IDE 執行程式時,檢查器會覆蓋此行為,以便錯誤也能被路由到 IDE 的控制檯,從而允許你檢查訊息中提到的物件。

當在構建階段發生錯誤時,系統會呼叫 ErrorWidget.builder 回撥來構建一個用於替代失敗元件的元件。預設情況下,在除錯模式下,這會顯示一條紅色錯誤訊息;在釋出模式下,這會顯示一個灰色背景。

當錯誤發生在沒有 Flutter 回撥的呼叫棧上時,它們由 PlatformDispatcher 的錯誤回撥處理。預設情況下,這隻會列印錯誤,不會執行其他操作。

你可以自定義這些行為,通常是在 void main() 函式中設定它們的值。

下面解釋了每種錯誤型別的處理方式。底部提供了一個處理所有型別錯誤的程式碼片段。儘管你可以直接複製貼上該片段,但我們建議你先熟悉每種錯誤型別。

Flutter 捕獲的錯誤

#

例如,如果你希望在釋出模式下每當 Flutter 捕獲到錯誤時立即退出應用程式,可以使用以下處理器:

dart
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...

此處理器也可用於向日志記錄服務報告錯誤。有關更多詳細資訊,請參閱我們的“向服務報告錯誤”的烹飪指南章節 (reporting errors to a service)。

為構建階段錯誤定義自定義錯誤元件

#

要定義一個自定義錯誤元件,以便在構建器無法構建元件時顯示,請使用 MaterialApp.builder

dart
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 未捕獲的錯誤

#

考慮一個呼叫非同步函式(例如 MethodChannel.invokeMethod 或幾乎任何外掛)的 onPressed 回撥。例如:

dart
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

dart
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());
}

處理所有型別的錯誤

#

假設你希望在出現任何異常時退出應用程式,並在元件構建失敗時顯示自定義錯誤元件——你可以基於以下程式碼片段進行錯誤處理:

dart
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');
      },
    );
  }
}