Capture and processing of Error in fluent

Keywords: Flutter

catalogue

preface

Capture Flutter error

Custom ErrorWidget

Unable to capture errors

Complete code

preface

The fluent framework can catch errors during runtime, including construction, layout and drawing.

All Flutter errors are called back to the method   FlutterError.onError   Capture. By default, the   FlutterError.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 build, the callback function   ErrorWidget.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 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 generated by the zone in the occurrence area   Zone   handle.   Zone   By default, only errors are printed and nothing else is done.

These callback methods can be overridden, usually in   void main()   Method.

Let's see how to deal with it.

Capture Flutter error

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 have rewritten flutterror.onerror to capture errors. The first line of code is to display errors to the console, so that I can easily see errors 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
  });
}

Note that if your application invokes the WidgetsFlutterBinding.ensureInitialized() method in runApp to do some initialization operations (such as Firebase.initializeApp()), you must call WidgetsFlutterBinding.ensureInitialized() in runZonedGuarded:

runZonedGuarded(() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

If 'WidgetsFlutterBinding.ensureInitialized()' is 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:

 

Posted by NeoPuma on Tue, 26 Oct 2021 00:30:58 -0700