跳到主内容

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