handleRequestAppExit method
Handles any requests for application exit that may be received on the SystemChannels.platform method channel.
By default, returns ui.AppExitResponse.exit.
Not all exits are cancelable, so not all exits will call this function. Do not rely on this function as a place to save critical data, because you will be disappointed. There are a number of ways that the application can exit without letting the application know first: power can be unplugged, the battery removed, the application can be killed in a task manager or command line, or the device could have a rapid unplanned disassembly (i.e. it could explode). In all of those cases (and probably others), no notification will be given to the application that it is about to exit.
To create a local project with this code sample, run:
flutter create --sample=services.ServicesBinding.handleRequestAppExit.1 mysample
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// Flutter code sample for [ServicesBinding.handleRequestAppExit].
void main() {
runApp(const ApplicationExitExample());
}
class ApplicationExitExample extends StatelessWidget {
const ApplicationExitExample({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(body: Body()),
);
}
}
class Body extends StatefulWidget {
const Body({super.key});
@override
State<Body> createState() => _BodyState();
}
class _BodyState extends State<Body> with WidgetsBindingObserver {
bool _shouldExit = false;
String lastResponse = 'No exit requested yet';
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Future<void> _quit() async {
final AppExitType exitType =
_shouldExit ? AppExitType.required : AppExitType.cancelable;
setState(() {
lastResponse = 'App requesting ${exitType.name} exit';
});
await ServicesBinding.instance.exitApplication(exitType);
}
@override
Future<AppExitResponse> didRequestAppExit() async {
final AppExitResponse response =
_shouldExit ? AppExitResponse.exit : AppExitResponse.cancel;
setState(() {
lastResponse = 'App responded ${response.name} to exit request';
});
return response;
}
void _radioChanged(bool? value) {
value ??= true;
if (_shouldExit == value) {
return;
}
setState(() {
_shouldExit = value!;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RadioListTile<bool>(
title: const Text('Do Not Allow Exit'),
groupValue: _shouldExit,
value: false,
onChanged: _radioChanged,
),
RadioListTile<bool>(
title: const Text('Allow Exit'),
groupValue: _shouldExit,
value: true,
onChanged: _radioChanged,
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: _quit,
child: const Text('Quit'),
),
const SizedBox(height: 30),
Text(lastResponse),
],
),
),
);
}
}
See also:
- WidgetsBindingObserver.didRequestAppExit, which can be overridden to respond to this message.
- WidgetsBinding.handleRequestAppExit which overrides this method to notify its observers.
Implementation
@override
Future<AppExitResponse> handleRequestAppExit() async {
bool didCancel = false;
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
if ((await observer.didRequestAppExit()) == AppExitResponse.cancel) {
didCancel = true;
// Don't early return. For the case where someone is just using the
// observer to know when exit happens, we want to call all the
// observers, even if we already know we're going to cancel.
}
}
return didCancel ? AppExitResponse.cancel : AppExitResponse.exit;
}