Introduction to the

Although abnormalities in Flutter do not directly lead to APP crash as Native does, they should not be ignored. For example, if a widget fails to build, Or a network request fails to resolve, so we need a set of rules for FLUTTER to catch exceptions. The following are the types of exceptions, three ways of global exception capture, and several forms of exception reporting. When looking at the Isolate, Future, FlutterError onError, relevant code of practice.

Abnormalities common in Flutter

The most common problem with Flutter is null-pointer anomalies. The optional types of Flutter have always been a sore point in the language of Flutter. In short, there is a big gap between Flutter data structure conversion and optional types and mobile languages.

Dictionary conversions, type overcasts, file reads, network request errors, layout overflows, array overruns, plug-in communication exceptions, etc., are usually described by Error and Exception

1.Error: Used to define the program execution Error object

Error (dart.core)
    AsyncError (dart.async) 
    JsonUnsupportedObjectError (dart.convert)
        JsonCyclicError (dart.convert)
    LateInitializationErrorImpl (dart._internal)
    FlutterError (assertions.dart)
    RemoteError (dart.isolate)
    UnderflowError (quiver.async)
    MatchError (quiver.testing.equality)
    FallThroughError (dart.core)
    CastError (dart.core)
    UnsupportedError (dart.core)
        UnimplementedError (dart.core)
    ConcurrentModificationError (dart.core)
    LateInitializationError (dart.core)
        LateInitializationErrorImpl (dart._internal)
    OutOfMemoryError (dart.core)
    AbstractClassInstantiationError (dart.core)
    NoSuchMethodError (dart.core)
    TypeError (dart.core)
    UnimplementedError (dart.core)
    NullThrownError (dart.core)
    AssertionError (dart.core)
        FlutterError (assertions.dart)
    StackOverflowError (dart.core)
    CyclicInitializationError (dart.core)
    StateError (dart.core)
    ArgumentError (dart.core)
        IndexError (dart.core)
        RangeError (dart.core)
Copy the code

2.Exception: Manually thrown by dartVM and custom DART code

Exception (dart.core)
    DeferredLoadException (dart.async)
    TimeoutException (dart.async)
    IsolateSpawnException (dart.isolate)
    IOException (dart.io)
        HttpException (dart._http)
        WebSocketException (dart._http)
        FileSystemException (dart.io)
        ProcessException (dart.io)
        SignalException (dart.io)
        TlsException (dart.io)
        SocketException (dart.io)
        StdoutException (dart.io)
        StdinException (dart.io)
    PlatformException (message_codec.dart)
    MissingPluginException (message_codec.dart)
    TickerCanceled (ticker.dart)
    NetworkImageLoadException (image_provider.dart)
    PathException (path_exception.dart)
    UsageException (usage_exception.dart)
    SourceSpanException (span_exception.dart)
        MultiSourceSpanException (span_exception.dart)
        SourceSpanFormatException (span_exception.dart)
    ImageException (image_exception.dart)
    ParserException (petitparser.core.contexts.exception)
    XmlException (xml.utils.exceptions)
        XmlNodeTypeException (xml.utils.exceptions)
        XmlParserException (xml.utils.exceptions)
        XmlParentException (xml.utils.exceptions)
        XmlTagException (xml.utils.exceptions)
    ClosedException (closed_exception.dart)
    RemoteException (remote_exception.dart)
        _RemoteTestFailure (remote_exception.dart)
    FormatException (dart.core)
        ArchiveException (archive_exception.dart)
        ArgParserException (arg_parser_exception.dart)
        MultiSourceSpanFormatException (span_exception.dart)
        SourceSpanFormatException (span_exception.dart)
        XmlParserException (xml.utils.exceptions)
    IntegerDivisionByZeroException (dart.core)
    _Exception (dart.core)
Copy the code
  • Error and Exception both represent exceptions, but it seems that error-level logs are more prone to program execution errors, unpredictable problems, such as exceptions thrown by the DART VM, and exceptions with higher data severity levels, which may even cause the program to crash. Exceptions are more self-defined exceptions, predicted problems, and corresponding try catch to deal with such cases.

  • Therefore, we are required to have a strong sense of security in program development, reasonably use Exception to define the possible exceptions of the function, and do a good job of the corresponding try catch and remarks

  • For exceptions of the Error type, such as TypeError, do validation in advance to ensure code accuracy, and for asynchronous operations such as Future and Stream, use try if you use the await keyword Catch, otherwise it will directly block the code executed after the block, especially during program startup.

Anomaly capture in Flutter

By reading the source code of the Flutter framework layer, it is not difficult to find that exceptions are mainly caught by Isolate, Zone, and flutter. Error. In addition, Future and Stream encapsulated based on Zone can be caught. Because their dependencies are as follows:

Stream -> Future -> Zone -> ParentZone -> Isolate Stream and Future are mainly used to write business logic. We can either catch or ignore them depending on the business scenario. If we have keywords like await, we must use exception catching, otherwise it will throw a line directly into the current zone and block the execution of the following code.

After registering the Isolate and currentZone at startup, and the FlutterError. OnError event, all app exceptions will be retrieved, and the current exception stack will be recorded.

You can also send the exception stack data to the background, send an email to the developer, or display the exception stack information on the widget directly by setting a backdoor switch.

Flutter error capture

  • It mainly focuses on the exception output of the Flutter framework layer, such as widget building, image reading,RenderObject drawing, click event distribution, test framework, and statistical analysis. The related classes are as follows:
dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart:
packages/flutter/lib/src/foundation/assertions.dart:
packages/flutter/lib/src/gestures/binding.dart:
packages/flutter/lib/src/gestures/pointer_router.dart:
packages/flutter/lib/src/painting/image_provider.dart:
packages/flutter/lib/src/widgets/fade_in_image.dart:
packages/flutter/lib/src/widgets/framework.dart:
packages/flutter/lib/src/widgets/image.dart:
packages/flutter/lib/src/widgets/widget_inspector.dart:
packages/flutter/test/rendering/rendering_tester.dart:
packages/flutter_test/lib/src/binding.dart:
Copy the code
  • use
    FlutterError.onError = (FlutterErrorDetails details) async {
      _reportError(details.exception, details.stack, errorDetails: details);
    };
Copy the code

Zone and Isolate exception capture

  • Create a new Zone to catch exceptions. This approach has some limitations. It can only catch exceptions inside the Zone.
    runZonedGuarded<Future<void>>(() async {
      if (ensureInitialized) {
        WidgetsFlutterBinding.ensureInitialized();
      }
      runApp(rootWidget);
    }, (dynamic error, StackTrace stackTrace) {
      _reportError(error, stackTrace);
    });
Copy the code
  • The Isolate provides an independent process space for flutter, and application execution depends on the creation of the Isolate. All functions including zone. run run under the corresponding Isolate ErrorListener can implement global error listening,
  Isolate.current.addErrorListener(new RawReceivePort((dynamic pair) async {
        var isolateError = pair as List<dynamic>;
        _reportError(
          isolateError.first.toString(),
          isolateError.last.toString(),
        );
      }).sendPort);
Copy the code

Handling abnormal data

The printed stack information can be sent to the specified background service for testing or sent in the form of email for troubleshooting In addition, Flutter provides the constructor of ErrorWidgets. There are two usage scenarios for Flutter, which are limited to the build of the Widget. In practice, we can save a global GlobalKey to store the context, so that we can create the wrong Wi in other abnormal parts Dget is displayed on the screen.

packages/flutter/lib/src/widgets/layout_builder.dart:
  102          } catch (e, stack) {
  103:           built = ErrorWidget.builder(
  104              _debugReportException(

  118        } catch (e, stack) {
  119:         built = ErrorWidget.builder(
  120            _debugReportException(

packages/flutter/lib/src/widgets/sliver.dart:
  1628    FlutterError.reportError(details);
  1629:   return ErrorWidget.builder(details);
Copy the code

conclusion

1, do not at any time for the type is not null, as long as it is not 100% not null must be preprocessed, set the default value or add optional operation symbols, such as optialValue? The property or optialValue?? 0

Expection defines and captures possible exceptions, such as parsing, type inference, cache reads, etc

try{
  final userInfo = await servie.getUserInfo();
} on NetExpection catch (e, string){
   ...
}
Copy the code

Define global exception catching

    FlutterError.onError = (FlutterErrorDetails details) async {
      ...
    };
        FlutterError.onError = (FlutterErrorDetails details) async {
      _reportError(details.exception, details.stack, errorDetails: details);
    };
    Isolate.current.addErrorListener(new RawReceivePort((dynamic pair) async {
        ...
    }).sendPort);
    runZonedGuarded<Future<void>>(() async {
      if (ensureInitialized) {
        WidgetsFlutterBinding.ensureInitialized();
      }
      runApp(rootWidget);
    }, (dynamic error, StackTrace stackTrace) {
      ...
    });
Copy the code

Get the current context via **GlobalKey** and print the error message to the screen via the widget; In the actual use of time will be more frequent, it is recommended to set a rear door switch, selective pop-up; Continue to expand, send mail call API, send to the background; At this point, a simple bugReport collection is complete, with a few dozen lines of code if you don’t pursue typography.

  • Future and zone-related exception capture tests
class CustomException implements Exception { CustomException({String message}); } /** - When a Future registers an OnError event, it will intercept all other OnError event results: start end onError Instance of 'CustomException' `StackTrace.current` */ void testFutureOnErrorHasMostPriority(){ print('start'); runZonedGuarded((){ final future = Future.error(CustomException(message: 'CustomException')); future.then((value){ print('then value $value'); },onError: (e,s){// Print ('onError $e 'stacktrace.current '); } ).catchError((e, s){ print('catchError $e `StackTrace.current`'); return null; }, test: (object) { if (object is CustomException) { print('test object $object true'); Return true; // This is a recoverable error, and 'catchError' continues processing. } else { print('test object $object false'); // Error "runZonedGuarded" cannot be guarded when the system is false. }}); },(e,s){ print('runZonedGuarded onError: $e $s'); }); print('end'); } /** - Start end test object Instance of catchError (catchError 'CustomException' true catchError Instance of 'CustomException' `StackTrace.current` Exited */ void testFutureOnErrorDelegateToSelfTestAndCatch(){ print('start'); runZonedGuarded((){ final future = Future.error(CustomException()); future.then((value){ print('then value $value'); }).catchError((e, s){ print('catchError $e `StackTrace.current`'); return null; }, test: (object) { if (object is CustomException) { print('test object $object false'); return false; } else { print('test object $object false'); return false; }}); },(e,s){ print('runZonedGuarded onError: $e $s'); }); print('end'); } /** - Future Try to keep system gates guarded when exceptions cannot be handled. Start end runZonedGuarded onError: Instance of 'CustomException' Exited */ void testFutureOnErrorDelegateToParentZoneIfUnCatch(){ print('start'); runZonedGuarded((){ final future = Future.error(CustomException()); future.then((value){ print('then value $value'); }); },(e,s){ print('runZonedGuarded onError: $e $s'); }); print('end'); }Copy the code

Follow me on Gitee for more learning information