I tried to test the behavior of future, but
Throwing an exception in future will break the dart main thread
However, the reverse is true in the Flutter:
Dart Code
Future(() async {
await Future.delayed(Duration(seconds: 10));
print("TimeOut");
}).timeout(Duration(seconds: 5));
Future(() async {
await Future.delayed(Duration(seconds: 15));
print("AAAAAAA");
});
in Dart use the code dart run ./a.dart
Unhandled exception:
TimeoutException after 0:00:05.000000: Future not completed
in Flutter:
E/flutter (11789): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: TimeoutException after 0:00:05.000000: Future not completed
E/flutter (11789):
I/flutter (11789): TimeOut
I/flutter (11789): AAAAAAA
Why ?
CodePudding user response:
The difference between Dart and Flutter is that Flutter catches all unhandled exceptions and just prints them out (including the stack trace). This is on purpose and the secret is that Flutter registers a callback to the static class function FlutterError.onError and the default implementation is the function FlutterError.presentError. Some more details on the official docs: Handling errors in Flutter
Disable terminating on fatal errors in Dart
It's possible to disable terminating the app/script on fatal errors by calling Isolate.setErrorsFatal with false
. For example, to keep async code running even if an unhandled exception is thrown just do this.
void main () {
Isolate.current.setErrorsFatal(false); // <- Here
Future(() async {
await Future.delayed(Duration(seconds: 10));
print("TimeOut");
}).timeout(Duration(seconds: 5));
Future(() async {
await Future.delayed(Duration(seconds: 15));
print("AAAAAAA");
});
}
And the output is going to be:
TimeOut
AAAAAAA
Dart with the same behaviour as Flutter
The following code simulates the same thing Flutter does in Dart with runZonedGuarded:
import 'dart:async';
void main(List<String> args) {
runZonedGuarded(program, errorHandler);
}
void program() {
Future(() async {
await Future.delayed(Duration(seconds: 10));
print("TimeOut");
}).timeout(Duration(seconds: 5));
Future(() async {
await Future.delayed(Duration(seconds: 15));
print("AAAAAAA");
});
}
void errorHandler(Object error, StackTrace stack) {
print('Unhandled exception:\n$error');
}
The output is going to be the following in Dart:
Unhandled exception:
TimeoutException after 0:00:05.000000: Future not completed
TimeOut
AAAAAAA
Flutter with the same behaviour as Dart
On the other hand, it's possible to do the same thing in Flutter as Dart does. I.e. kills the app on whenever unhandled exception. It's just a matter of using the runZonedGuarded again:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
void main() {
runZonedGuarded(() async {
runApp(const MyApp());
}, (Object error, StackTrace stack) {
print('Unhandled exception:\n$error');
exit(1);
});
}
void program() {
Future(() async {
await Future.delayed(Duration(seconds: 10));
print("TimeOut");
}).timeout(Duration(seconds: 5));
Future(() async {
await Future.delayed(Duration(seconds: 15));
print("AAAAAAA");
});
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
program();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) => const Scaffold(
body: Center(child: Text('The app is going to exit in 5 seconds...')),
),
);
}
}
The output is going to be the following:
flutter: Unhandled exception:
TimeoutException after 0:00:05.000000: Future not completed
Lost connection to device.