Unverified Commit 0aba94f4 authored by Bruno Leroux's avatar Bruno Leroux Committed by GitHub

Fix IconButton leaks its internal MaterialStatesController (#130720)

## Description

This PR adds a call to dispose the internal `MaterialStatesController` instantiated by `_SelectableIconButtonState`.

I found this memory leak while working on M2/M3 test update for `about_test.dart`. This memory leak only happens when using M3 because `IconButton` relies on `_SelectableIconButton` only when useMaterial3 is true:

https://github.com/flutter/flutter/blob/3a1190a5a85c3e6a0cf3a9c30f34548fdd48ac1e/packages/flutter/lib/src/material/icon_button.dart#L671-L721

## Related Issue

Fixes https://github.com/flutter/flutter/issues/130708

## Tests

Adds 1 test.
parent ec508319
...@@ -880,6 +880,12 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> { ...@@ -880,6 +880,12 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> {
), ),
); );
} }
@override
void dispose() {
statesController.dispose();
super.dispose();
}
} }
class _IconButtonM3 extends ButtonStyleButton { class _IconButtonM3 extends ButtonStyleButton {
......
...@@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../foundation/leak_tracking.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart'; import 'feedback_tester.dart';
...@@ -2729,18 +2730,18 @@ void main() { ...@@ -2729,18 +2730,18 @@ void main() {
final ColorScheme lightScheme = const ColorScheme.light().copyWith(onSurfaceVariant: const Color(0xffe91e60)); final ColorScheme lightScheme = const ColorScheme.light().copyWith(onSurfaceVariant: const Color(0xffe91e60));
// Brightness.dark // Brightness.dark
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(colorScheme: lightScheme, useMaterial3: true,), theme: ThemeData(colorScheme: lightScheme, useMaterial3: true,),
home: Scaffold( home: Scaffold(
body: IconTheme.merge( body: IconTheme.merge(
data: const IconThemeData(size: 26), data: const IconThemeData(size: 26),
child: IconButton( child: IconButton(
icon: const Icon(Icons.account_box), icon: const Icon(Icons.account_box),
onPressed: () {}, onPressed: () {},
), ),
), ),
)
) )
)
); );
Color? iconColor0() => _iconStyle(tester, Icons.account_box)?.color; Color? iconColor0() => _iconStyle(tester, Icons.account_box)?.color;
...@@ -2770,6 +2771,25 @@ void main() { ...@@ -2770,6 +2771,25 @@ void main() {
expect(tester.takeException(), isNull); expect(tester.takeException(), isNull);
}); });
testWidgetsWithLeakTracking('Material3 - IconButton memory leak', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/issues/130708.
Widget buildWidget(bool showIconButton) {
return showIconButton
? MaterialApp(
theme: ThemeData(useMaterial3: true),
home: IconButton(
onPressed: () { },
icon: const Icon(Icons.search),
),
)
: const SizedBox();
}
await tester.pumpWidget(buildWidget(true));
await tester.pumpWidget(buildWidget(false));
// No exception is thrown.
});
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment