Skip to content

Commit 266cdf0

Browse files
Fix memory leaks in FloatingActionButton (#146711)
1 parent 46fbb73 commit 266cdf0

File tree

5 files changed

+68
-38
lines changed

5 files changed

+68
-38
lines changed

packages/flutter/lib/src/material/scaffold.dart

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
13201320
// The animations applied to the Floating Action Button when it is entering or exiting.
13211321
// Controls the previous widget.child as it exits.
13221322
late AnimationController _previousController;
1323+
CurvedAnimation? _previousExitScaleAnimation;
1324+
CurvedAnimation? _previousExitRotationCurvedAnimation;
1325+
CurvedAnimation? _currentEntranceScaleAnimation;
13231326
late Animation<double> _previousScaleAnimation;
13241327
late TrainHoppingAnimation _previousRotationAnimation;
13251328
// The animations to run, considering the widget's fabMoveAnimation and the current/previous entrance/exit animations.
@@ -1352,6 +1355,9 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
13521355
@override
13531356
void dispose() {
13541357
_previousController.dispose();
1358+
_previousExitScaleAnimation?.dispose();
1359+
_previousExitRotationCurvedAnimation?.dispose();
1360+
_currentEntranceScaleAnimation?.dispose();
13551361
_disposeAnimations();
13561362
super.dispose();
13571363
}
@@ -1402,19 +1408,24 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
14021408
}
14031409

14041410
void _updateAnimations() {
1411+
_previousExitScaleAnimation?.dispose();
14051412
// Get the animations for exit and entrance.
1406-
final CurvedAnimation previousExitScaleAnimation = CurvedAnimation(
1413+
_previousExitScaleAnimation = CurvedAnimation(
14071414
parent: _previousController,
14081415
curve: Curves.easeIn,
14091416
);
1410-
final Animation<double> previousExitRotationAnimation = Tween<double>(begin: 1.0, end: 1.0).animate(
1411-
CurvedAnimation(
1417+
_previousExitRotationCurvedAnimation?.dispose();
1418+
_previousExitRotationCurvedAnimation = CurvedAnimation(
14121419
parent: _previousController,
14131420
curve: Curves.easeIn,
1414-
),
1421+
);
1422+
1423+
final Animation<double> previousExitRotationAnimation = Tween<double>(begin: 1.0, end: 1.0).animate(
1424+
_previousExitRotationCurvedAnimation!
14151425
);
14161426

1417-
final CurvedAnimation currentEntranceScaleAnimation = CurvedAnimation(
1427+
_currentEntranceScaleAnimation?.dispose();
1428+
_currentEntranceScaleAnimation = CurvedAnimation(
14181429
parent: widget.currentController,
14191430
curve: Curves.easeIn,
14201431
);
@@ -1425,8 +1436,8 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
14251436
final Animation<double> moveRotationAnimation = widget.fabMotionAnimator.getRotationAnimation(parent: widget.fabMoveAnimation);
14261437

14271438
// Aggregate the animations.
1428-
_previousScaleAnimation = AnimationMin<double>(moveScaleAnimation, previousExitScaleAnimation);
1429-
_currentScaleAnimation = AnimationMin<double>(moveScaleAnimation, currentEntranceScaleAnimation);
1439+
_previousScaleAnimation = AnimationMin<double>(moveScaleAnimation, _previousExitScaleAnimation!);
1440+
_currentScaleAnimation = AnimationMin<double>(moveScaleAnimation, _currentEntranceScaleAnimation!);
14301441
_extendedCurrentScaleAnimation = _currentScaleAnimation.drive(CurveTween(curve: const Interval(0.0, 0.1)));
14311442

14321443
_previousRotationAnimation = TrainHoppingAnimation(previousExitRotationAnimation, moveRotationAnimation);

packages/flutter/test/widgets/color_filter_test.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ library;
1111
import 'package:flutter/material.dart';
1212
import 'package:flutter/rendering.dart';
1313
import 'package:flutter_test/flutter_test.dart';
14+
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
1415

1516
import '../impeller_test_helpers.dart';
1617

@@ -30,7 +31,11 @@ void main() {
3031
);
3132
});
3233

33-
testWidgets('Color filter - sepia', (WidgetTester tester) async {
34+
testWidgets('Color filter - sepia',
35+
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
36+
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: const <String>['CurvedAnimation']),
37+
(WidgetTester tester) async {
38+
3439
const ColorFilter sepia = ColorFilter.matrix(<double>[
3540
0.39, 0.769, 0.189, 0, 0, //
3641
0.349, 0.686, 0.168, 0, 0, //

packages/flutter/test/widgets/focus_traversal_test.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
88
import 'package:flutter/material.dart';
99
import 'package:flutter/services.dart';
1010
import 'package:flutter_test/flutter_test.dart';
11+
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
1112

1213
import 'semantics_tester.dart';
1314

@@ -2820,7 +2821,10 @@ void main() {
28202821
expect(events.length, 2);
28212822
}, variant: KeySimulatorTransitModeVariant.all());
28222823

2823-
testWidgets('Focus traversal does not throw when no focusable is available in a group', (WidgetTester tester) async {
2824+
testWidgets('Focus traversal does not throw when no focusable is available in a group',
2825+
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
2826+
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: const <String>['CurvedAnimation']),
2827+
(WidgetTester tester) async {
28242828
await tester.pumpWidget(const MaterialApp(home: Scaffold(body: ListTile(title: Text('title')))));
28252829
final FocusNode? initialFocus = primaryFocus;
28262830
await tester.sendKeyEvent(LogicalKeyboardKey.tab);

packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:flutter/material.dart';
66
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
78

89
class TestItem extends StatelessWidget {
910
const TestItem({ super.key, required this.item, this.width, this.height });
@@ -40,7 +41,10 @@ Widget buildFrame({ int? count, double? width, double? height, Axis? scrollDirec
4041
}
4142

4243
void main() {
43-
testWidgets('SliverPrototypeExtentList.builder test', (WidgetTester tester) async {
44+
testWidgets('SliverPrototypeExtentList.builder test',
45+
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
46+
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: const <String>['CurvedAnimation']),
47+
(WidgetTester tester) async {
4448
await tester.pumpWidget(
4549
MaterialApp(
4650
home: Scaffold(

packages/flutter/test/widgets/text_golden_test.dart

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ library;
1010

1111
import 'package:flutter/material.dart';
1212
import 'package:flutter_test/flutter_test.dart';
13+
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
1314

1415
void main() {
1516
testWidgets('Centered text', (WidgetTester tester) async {
@@ -188,42 +189,47 @@ void main() {
188189
);
189190
});
190191

191-
testWidgets('Text Fade', (WidgetTester tester) async {
192-
await tester.pumpWidget(
193-
MaterialApp(
194-
theme: ThemeData(useMaterial3: false),
195-
home: Scaffold(
196-
backgroundColor: Colors.transparent,
197-
body: RepaintBoundary(
198-
child: Center(
199-
child: Container(
200-
width: 200.0,
201-
height: 200.0,
202-
color: Colors.green,
203-
child: Center(
204-
child: Container(
205-
width: 100.0,
206-
color: Colors.blue,
207-
child: const Text(
208-
'Pp PPp PPPp PPPPp PPPPpp PPPPppp PPPPppppp ',
209-
style: TextStyle(color: Colors.black),
210-
maxLines: 3,
211-
overflow: TextOverflow.fade,
192+
testWidgets(
193+
'Text Fade',
194+
// TODO(polina-c): remove when fixed https://github.com/flutter/flutter/issues/145600 [leak-tracking-opt-in]
195+
experimentalLeakTesting: LeakTesting.settings.withTracked(classes: const <String>['CurvedAnimation']),
196+
(WidgetTester tester) async {
197+
await tester.pumpWidget(
198+
MaterialApp(
199+
theme: ThemeData(useMaterial3: false),
200+
home: Scaffold(
201+
backgroundColor: Colors.transparent,
202+
body: RepaintBoundary(
203+
child: Center(
204+
child: Container(
205+
width: 200.0,
206+
height: 200.0,
207+
color: Colors.green,
208+
child: Center(
209+
child: Container(
210+
width: 100.0,
211+
color: Colors.blue,
212+
child: const Text(
213+
'Pp PPp PPPp PPPPp PPPPpp PPPPppp PPPPppppp ',
214+
style: TextStyle(color: Colors.black),
215+
maxLines: 3,
216+
overflow: TextOverflow.fade,
217+
),
212218
),
213219
),
214220
),
215221
),
216222
),
217223
),
218224
),
219-
),
220-
);
225+
);
221226

222-
await expectLater(
223-
find.byType(RepaintBoundary).first,
224-
matchesGoldenFile('text_golden.Fade.png'),
225-
);
226-
});
227+
await expectLater(
228+
find.byType(RepaintBoundary).first,
229+
matchesGoldenFile('text_golden.Fade.png'),
230+
);
231+
},
232+
);
227233

228234
testWidgets('Default Strut text', (WidgetTester tester) async {
229235
await tester.pumpWidget(

0 commit comments

Comments
 (0)