Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix IconButton leaks its internal MaterialStatesController #130720

Merged
merged 1 commit into from Jul 20, 2023

Conversation

bleroux
Copy link
Contributor

@bleroux bleroux commented Jul 17, 2023

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:

if (theme.useMaterial3) {
final Size? minSize = constraints == null
? null
: Size(constraints!.minWidth, constraints!.minHeight);
final Size? maxSize = constraints == null
? null
: Size(constraints!.maxWidth, constraints!.maxHeight);
ButtonStyle adjustedStyle = styleFrom(
visualDensity: visualDensity,
foregroundColor: color,
disabledForegroundColor: disabledColor,
focusColor: focusColor,
hoverColor: hoverColor,
highlightColor: highlightColor,
padding: padding,
minimumSize: minSize,
maximumSize: maxSize,
iconSize: iconSize,
alignment: alignment,
enabledMouseCursor: mouseCursor,
disabledMouseCursor: mouseCursor,
enableFeedback: enableFeedback,
);
if (style != null) {
adjustedStyle = style!.merge(adjustedStyle);
}
Widget effectiveIcon = icon;
if ((isSelected ?? false) && selectedIcon != null) {
effectiveIcon = selectedIcon!;
}
Widget iconButton = effectiveIcon;
if (tooltip != null) {
iconButton = Tooltip(
message: tooltip,
child: effectiveIcon,
);
}
return _SelectableIconButton(
style: adjustedStyle,
onPressed: onPressed,
autofocus: autofocus,
focusNode: focusNode,
isSelected: isSelected,
variant: _variant,
child: iconButton,
);
}

Related Issue

Fixes #130708

Tests

Adds 1 test.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. labels Jul 17, 2023
@bleroux bleroux requested a review from QuncCccccc July 17, 2023 15:21
Copy link
Contributor

@QuncCccccc QuncCccccc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for add this fix! Just left one comment for the unit test:)

@@ -2770,6 +2772,56 @@ void main() {

expect(tester.takeException(), isNull);
});

testWidgetsWithLeakTracking('IconButton should dispose its internal MaterialStatesController', (WidgetTester tester) async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this test to packages/flutter/test/material/about_test.dart? Seems the LicensePage() is only tested in that file.

Copy link
Contributor Author

@bleroux bleroux Jul 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually we keep the test as close as possible to the fix. I agree that relying on LicensePage is not great but I was not able to figure out another way to reproduce the memory leak.
It's also true that this very same test will be part of the PR I'm working on for about_test.dart M3 migration.

I'm not used to work on PR related to leaks, maybe someone can give us guidance?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think to reproduce the issue, in icon_button_test.dart, we can try to pump an IconButton for the first time and then pump other widgets to see if there's any memory leak. Also checked other examples, looks like we also need to call TestWidgetsWithLeakingTracking instead of TestWidgets.

Try this. The memory leak can be reproduced when we don't have the fix.

testWidgetsWithLeakTracking('Material3 - IconButton memory leak', (WidgetTester tester) async {
  bool isSelected = false;
  Widget buildWidget(bool showIconButton) {
    return showIconButton
      ? MaterialApp(
        theme: ThemeData(useMaterial3: true),
        home: IconButton(
          onPressed: () { },
          isSelected: isSelected,
          icon: const Icon(Icons.search),
        ))
      : const SizedBox();
  }
  await tester.pumpWidget(buildWidget(true));
  await tester.pumpWidget(buildWidget(false));
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revisiting this, I was able to write a test which does not depend on LicensePage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice! I added a comment yesterday but didn't actually press the "submit review" button😂Sorry about that! But the response is similar to what you added.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! I really thought I tried something similar. This is way cleaner that my previous attempt, thanks!

@bleroux bleroux force-pushed the IconButton_leak branch 3 times, most recently from ca9fcb9 to 061c65b Compare July 18, 2023 07:43
@bleroux bleroux requested a review from QuncCccccc July 18, 2023 08:41
appBar: AppBar(title: const Text('AppBar')),
body: Builder(builder: (BuildContext context) {
return Center(
child: ElevatedButton(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we still didn't use IconButton here. I think the example I provided above might be enough to show there's no leaking.

Copy link
Contributor

@QuncCccccc QuncCccccc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM:) Just left one nit below.

@bleroux
Copy link
Contributor Author

bleroux commented Jul 19, 2023

Oops I misclicked.

@bleroux bleroux added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 20, 2023
@auto-submit auto-submit bot merged commit 0aba94f into flutter:master Jul 20, 2023
73 checks passed
@bleroux bleroux deleted the IconButton_leak branch July 20, 2023 08:00
auto-submit bot pushed a commit that referenced this pull request Jul 20, 2023
This PR updates unit tests in `about_test.dart` for M3 migration.

More info in #127064

- Two tests were failing in M3 due to a memory leak. As the memory leak is now fixed, see #130720, this two tests does not depend anymore on the Material version.

- Created several M3 tests related to typography and rendering changes.
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jul 21, 2023
Roll Flutter from d07e8aece184 to 9cfbf6b9fd40 (58 revisions)

flutter/flutter@d07e8ae...9cfbf6b

2023-07-21 engine-flutter-autoroll@skia.org Roll Packages from 674179f to 2266a76 (6 revisions) (flutter/flutter#131058)
2023-07-21 jhy03261997@gmail.com Add tests for navigation_drawer_theme_test.dart  (flutter/flutter#130465)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from f812cf373b6b to f5c1650c7acc (1 revision) (flutter/flutter#131037)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from 264685f0aecb to f812cf373b6b (1 revision) (flutter/flutter#131032)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from 8ff10f5a7667 to 264685f0aecb (1 revision) (flutter/flutter#131031)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from b5a6b1c9cba5 to 8ff10f5a7667 (5 revisions) (flutter/flutter#131029)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from 218b71cd7a45 to b5a6b1c9cba5 (1 revision) (flutter/flutter#131025)
2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter Engine from ab7d424d4467 to 218b71cd7a45 (2 revisions) (flutter/flutter#131024)
2023-07-21 stuartmorgan@google.com Use downgraded analyze for flutter/packages (flutter/flutter#130878)
2023-07-21 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#131022)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9b2ebf2afe00 to ab7d424d4467 (4 revisions) (flutter/flutter#131015)
2023-07-20 gspencergoog@users.noreply.github.com Add applyFocusChangeIfNeeded, have menus restore focus before activating (flutter/flutter#130536)
2023-07-20 christopherfujino@gmail.com Migrate more integration tests to process result matcher (flutter/flutter#130994)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 062079ba30b6 to 9b2ebf2afe00 (2 revisions) (flutter/flutter#131013)
2023-07-20 ian@hixie.ch Trivial grammar and wrapping fix for docs (flutter/flutter#130955)
2023-07-20 hans.muller@gmail.com Updated the ThemeData API example (flutter/flutter#130954)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from a3fc18514cd6 to 062079ba30b6 (3 revisions) (flutter/flutter#131010)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 6d7842d25f81 to a3fc18514cd6 (2 revisions) (flutter/flutter#131007)
2023-07-20 36861262+QuncCccccc@users.noreply.github.com Update `TextSelectionTheme`, `ThemeData`, `TimePicker`, and `TimePickerTheme` tests for M2/M3 (flutter/flutter#130547)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from c645eb6da8a9 to 6d7842d25f81 (1 revision) (flutter/flutter#130992)
2023-07-20 leroux_bruno@yahoo.fr Update AutoComplete test for M3 migration (flutter/flutter#130883)
2023-07-20 leroux_bruno@yahoo.fr Update about tests for M3 (flutter/flutter#130970)
2023-07-20 engine-flutter-autoroll@skia.org Roll Packages from 209db21 to 674179f (4 revisions) (flutter/flutter#130989)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from e40995da7869 to c645eb6da8a9 (1 revision) (flutter/flutter#130988)
2023-07-20 polinach@google.com Upgrade leak_tracker. (flutter/flutter#130951)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2df3b9c4b2a4 to e40995da7869 (2 revisions) (flutter/flutter#130985)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from b494143fb0bc to 2df3b9c4b2a4 (3 revisions) (flutter/flutter#130973)
2023-07-20 tessertaha@gmail.com Fix chip delete button tap target spilling into the label. (flutter/flutter#130896)
2023-07-20 leroux_bruno@yahoo.fr Fix IconButton leaks its internal MaterialStatesController (flutter/flutter#130720)
2023-07-20 leroux_bruno@yahoo.fr Update banner_theme_test.dart for M3 (flutter/flutter#130884)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 204625490ca1 to b494143fb0bc (1 revision) (flutter/flutter#130966)
2023-07-20 chingjun@google.com Make PollingDeviceDiscovery start the initial poll faster. (flutter/flutter#130755)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from c902fec1e3ce to 204625490ca1 (1 revision) (flutter/flutter#130962)
2023-07-20 ian@hixie.ch More documentation for MediaQuery and friends (flutter/flutter#130509)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 56e88e8b0eef to c902fec1e3ce (1 revision) (flutter/flutter#130960)
2023-07-20 ian@hixie.ch Automatically create the layer when setting hints in PaintingContext (flutter/flutter#130364)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from e2a36be2f084 to 56e88e8b0eef (1 revision) (flutter/flutter#130959)
2023-07-20 ian@hixie.ch Further clarify Stack documentation on overflowing (flutter/flutter#130776)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from eff70f7287f9 to e2a36be2f084 (2 revisions) (flutter/flutter#130956)
2023-07-20 47866232+chunhtai@users.noreply.github.com Can traverse if current focused node skips traversal (flutter/flutter#130812)
2023-07-20 ian@hixie.ch Document that you can't change initialRoute usefully (flutter/flutter#130450)
2023-07-20 engine-flutter-autoroll@skia.org Roll Flutter Engine from 7671e2f2a9fc to eff70f7287f9 (3 revisions) (flutter/flutter#130953)
2023-07-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 938140a974b0 to 7671e2f2a9fc (3 revisions) (flutter/flutter#130948)
2023-07-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0af285219809 to 938140a974b0 (1 revision) (flutter/flutter#130943)
2023-07-19 ian@hixie.ch Add docs to Route.maintainState (flutter/flutter#130638)
2023-07-19 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.20.4 to 2.21.0 (flutter/flutter#130941)
...
LouiseHsu pushed a commit to LouiseHsu/flutter that referenced this pull request Jul 31, 2023
…30720)

## 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 flutter#130708

## Tests

Adds 1 test.
LouiseHsu pushed a commit to LouiseHsu/flutter that referenced this pull request Jul 31, 2023
This PR updates unit tests in `about_test.dart` for M3 migration.

More info in flutter#127064

- Two tests were failing in M3 due to a memory leak. As the memory leak is now fixed, see flutter#130720, this two tests does not depend anymore on the Material version.

- Created several M3 tests related to typography and rendering changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

IconButton does not dispose its internal MaterialStatesController
2 participants