diff --git a/packages/flame/lib/src/game/game.dart b/packages/flame/lib/src/game/game.dart index 46e183301c..53f2e2e88b 100644 --- a/packages/flame/lib/src/game/game.dart +++ b/packages/flame/lib/src/game/game.dart @@ -213,6 +213,9 @@ abstract mixin class Game { /// do cleanups to avoid memory leaks. void onRemove() {} + /// Called when the GameWidget is disposed by Flutter. + void onDispose() {} + /// Called after the game has left the widget tree. /// This can be overridden to add logic that requires the game /// not be on the flutter widget tree anymore. diff --git a/packages/flame/lib/src/game/game_widget/game_widget.dart b/packages/flame/lib/src/game/game_widget/game_widget.dart index 61a5da0e61..fdf734c3ba 100644 --- a/packages/flame/lib/src/game/game_widget/game_widget.dart +++ b/packages/flame/lib/src/game/game_widget/game_widget.dart @@ -254,8 +254,14 @@ class GameWidgetState extends State> { _loaderFuture = null; } - void disposeCurrentGame() { + /// [disposeCurrentGame] is called by two flutter events - `didUpdateWidget` + /// and `dispose`. When the parameter [callGameOnDispose] is true, the + /// `currentGame`'s `onDispose` method will be called; otherwise, it will not. + void disposeCurrentGame({bool callGameOnDispose = false}) { currentGame.removeGameStateListener(_onGameStateChange); + if (callGameOnDispose) { + currentGame.onDispose(); + } } @override @@ -281,7 +287,7 @@ class GameWidgetState extends State> { @override void dispose() { super.dispose(); - disposeCurrentGame(); + disposeCurrentGame(callGameOnDispose: true); // If we received a focus node from the user, they are responsible // for disposing it if (widget.focusNode == null) { diff --git a/packages/flame/test/game/game_widget/game_widget_lifecycle_test.dart b/packages/flame/test/game/game_widget/game_widget_lifecycle_test.dart index 16914e6472..568b521847 100644 --- a/packages/flame/test/game/game_widget/game_widget_lifecycle_test.dart +++ b/packages/flame/test/game/game_widget/game_widget_lifecycle_test.dart @@ -30,6 +30,12 @@ class _MyGame extends FlameGame { super.onRemove(); events.add('onRemove'); } + + @override + void onDispose() { + super.onDispose(); + events.add('onDispose'); + } } class _TitlePage extends StatelessWidget { @@ -185,6 +191,11 @@ void main() { true, reason: 'onRemove was not called', ); + expect( + events.contains('onDispose'), + true, + reason: 'onDispose was not called', + ); }); testWidgets('on resize, parents are kept', (tester) async { @@ -229,6 +240,7 @@ void main() { 'onLoad', 'onMount', 'onRemove', + 'onDispose', 'onGameResize', 'onMount', ],