
The fluent framework can catch errors during runtime, including construction, layout and drawing.
All Flutter errors are called back to the method flutterror Onerror capture. By default, flutterror. Is called Dumperrortoconsole method, as indicated by the method name, dumps the error to the current device log. When the application is run from the IDE, the inspector overrides this method, and the error is also sent to the console of the IDE. You can check the error object in the console.
When an error occurs during construction, the callback function errorwidget The builder will be called to generate a new widget to replace the widget that failed to build. By default, an error page with a red background will be displayed in debug mode, and a blank page with a gray background will be displayed in release mode.
If errors occur when there is no Flutter callback on the call stack (it can be understood here that flutterror.onerror can only capture the errors of the main thread, while the errors of other asynchronous threads need to be captured by the Zone), they are handled by the Zone in the occurrence area. By default, Zone prints only errors and does nothing else.
These callback methods can be overridden, usually in the void main() method.
Let's see how to deal with it.
Capture Flutter error
Just rewrite the onError of flutterror, as follows
import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; void main() { FlutterError.onError = (FlutterErrorDetails details) { FlutterError.dumpErrorToConsole(details); if (kReleaseMode) ... //Handle online errors, such as statistical upload }; runApp(MyApp()); }
Above, we rewrite the flutterror Onerror, so that the error can be captured. The first line of code shows the error to the console, so that I can easily see the error on the console during development. The following code is to further handle errors in the online environment, such as statistical upload.
Custom ErrorWidget
As we know above, an error page will be displayed by default when an error occurs during construction, but this page is very unfriendly. We can customize an error page. Define a custom error widget to display when the builder fails to build the widget. Please use materialapp builder.
class MyApp extends StatelessWidget { ... @override Widget build(BuildContext context) { return MaterialApp( ... builder: (BuildContext context, Widget widget) { Widget error = Text('...rendering error...'); if (widget is Scaffold || widget is Navigator) error = Scaffold(body: Center(child: error)); ErrorWidget.builder = (FlutterErrorDetails errorDetails) => error; return widget; }, ); } }
In the builder under App, customize an error page and assign it to errorwidget Builder. In this way, a friendly page can be displayed when errors occur again.
Unable to capture errors
Suppose an onPressed callback calls an asynchronous method, such as methodchannel Invokemethod (or other plugin methods):
OutlinedButton( child: Text('Click me!'), onPressed: () async { final channel = const MethodChannel('crashy-custom-channel'); await channel.invokeMethod('blah'); }, ),
If invokeMethod throws an error, it will not be passed to flutterror Onerror, but directly enter the Zone of runApp.
If you want to catch such errors, use runZonedGuarded. The code is as follows:
import 'dart:async'; void main() { runZonedGuarded(() { runApp(MyApp()); }, (Object error, StackTrace stack) { ... //Processing error }); }
Please note that if your application calls WidgetsFlutterBinding. in runApp, EnsureInitialized () method has some initialization operations (such as Firebase.initializeApp()), and WidgetsFlutterBinding. must be invoked in runZonedGuarded. ensureInitialized():
runZonedGuarded(() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); }
If ` widgetsflutterbinding Ensureinitialized() ` when called externally, the error will not be caught.
Complete code
If you want to deal with all the above problems, the code is as follows:
import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; void main() { runZonedGuarded(() async { WidgetsFlutterBinding.ensureInitialized(); ... await myErrorsHandler.initialize(); FlutterError.onError = (FlutterErrorDetails details) { FlutterError.dumpErrorToConsole(details); myErrorsHandler.onError(details); }; runApp(MyApp()); }, (Object error, StackTrace stack) { myErrorsHandler.onError(error, stack); }); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( ... builder: (BuildContext context, Widget widget) { Widget error = Text('...rendering error...'); if (widget is Scaffold || widget is Navigator) error = Scaffold(body: Center(child: error)); ErrorWidget.builder = (FlutterErrorDetails errorDetails) => error; return widget; }, ); } }
First, handle asynchronous errors through runZonedGuarded, and then through flutterror Onerror processing. These errors can be processed centrally through a user-defined myErrorsHandler, such as statistics upload. Then you need to define a friendly error page in the app.