Skip to content

Calling setState in a MaterialStatesController listener and MaterialStateController.update causes Exception #138986

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

Closed
2 tasks done
ansolantz opened this issue Nov 24, 2023 · 2 comments · Fixed by #143453
Closed
2 tasks done
Assignees
Labels
a: error message Error messages from the Flutter framework d: api docs Issues with https://api.flutter.dev/ f: material design flutter/packages/flutter/material repository. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list r: fixed Issue is closed as already fixed in a newer version team-design Owned by Design Languages team triaged-design Triaged by Design Languages team

Comments

@ansolantz
Copy link

ansolantz commented Nov 24, 2023

Is there an existing issue for this?

Steps to reproduce

I need to perform a custom theming based on the state of a button so I use a MaterialStateController. However if the button is created in disabled state with a MaterialStateController, a "setState() or markNeedsBuild() called during build." exception is thrown on creation.

The reason appears to origin here: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/button_style_button.dart#L222

because initialising in disabled state causes notifyListeners to be called synchronously and if the listener needs to call setState, we get this problem.

Wrapping the addListener into a addPostFrameCallback call fixes this but I am not sure if that is the intended solution.

Expected results

It should be possible to create the button with a MaterialStateController in disabled state.

Actual results

The following assertion was thrown while dispatching notifications for MaterialStatesController:
setState() or markNeedsBuild() called during build.

Code sample

Code sample
class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final statesController = MaterialStatesController();
  @override
  void initState() {
    // Using addPostFramCallback removes the exception
    // WidgetsBinding.instance.addPostFrameCallback((_) {
    statesController.addListener(() {
      setState(() {
        print("Material state changed");
      });
    });
    //  });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Center(
        child: ElevatedButton(
          statesController: statesController,
          onPressed: null,
          child: Text('Press'),
        ),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.13.9, on macOS)
    • Flutter version 3.13.9 on channel stable 
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision d211f42860 (4 weeks ago), 2023-10-25 13:42:25 -0700
    • Engine revision 0545f8705d
    • Dart version 3.1.5
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
    • Android SDK at /
    • Platform android-33, build-tools 33.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.12.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/OLD_Android Studio_OLD.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)

[✓] VS Code (version 1.84.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.56.0
@huycozy huycozy added the in triage Presently being triaged by the triage team label Nov 27, 2023
@huycozy
Copy link
Member

huycozy commented Nov 27, 2023

Thank you for the report. Reproduced the issue on the latest stable and master channels.

Exception log
I/flutter ( 7378): Material state changed

======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for MaterialStatesController:
setState() or markNeedsBuild() called during build.

This MyHomePage widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: MyHomePage
  dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#b2573]]
  state: _MyHomePageState#28e34
The widget which was currently being built when the offending call was made was: KeyedSubtree-[GlobalKey#59313]
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:5042:9)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:5054:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1223:15)
#3      _MyHomePageState.initState.<anonymous closure> (package:reproduce_issues/m3state_138986.dart:28:7)
#4      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:433:24)
#5      MaterialStatesController.update (package:flutter/src/material/material_state.dart:762:7)
#6      _ButtonStyleState.initStatesController (package:flutter/src/material/button_style_button.dart:222:22)
#7      _ButtonStyleState.initState (package:flutter/src/material/button_style_button.dart:229:5)
#8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5611:55)
#9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:5456:5)
...     Normal element mounting (28 frames)
#37     Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
#38     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6893:36)
#39     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6905:32)
...     Normal element mounting (332 frames)
#371    Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
#372    MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6893:36)
#373    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6905:32)
...     Normal element mounting (483 frames)
#856    Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
#857    Element.updateChild (package:flutter/src/widgets/framework.dart:3846:18)
#858    _RawViewElement._updateChild (package:flutter/src/widgets/view.dart:291:16)
#859    _RawViewElement.mount (package:flutter/src/widgets/view.dart:314:5)
...     Normal element mounting (7 frames)
#866    Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
#867    Element.updateChild (package:flutter/src/widgets/framework.dart:3846:18)
#868    RootElement._rebuild (package:flutter/src/widgets/binding.dart:1354:16)
#869    RootElement.mount (package:flutter/src/widgets/binding.dart:1323:5)
#870    RootWidget.attach.<anonymous closure> (package:flutter/src/widgets/binding.dart:1276:18)
#871    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2844:19)
#872    RootWidget.attach (package:flutter/src/widgets/binding.dart:1275:13)
#873    WidgetsBinding.attachToBuildOwner (package:flutter/src/widgets/binding.dart:1088:27)
#874    WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:1070:5)
#875    WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:1056:7)
#879    _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
(elided 3 frames from class _Timer and dart:async-patch)
The MaterialStatesController sending notification was: MaterialStatesController#4bdbd({MaterialState.disabled})
====================================================================================================
flutter doctor -v (stable and master)
[✓] Flutter (Channel stable, 3.16.0, on macOS 14.1 23B74 darwin-x64, locale en-VN)
    • Flutter version 3.16.0 on channel stable at /Users/huynq/Documents/GitHub/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision db7ef5bf9f (8 hours ago), 2023-11-15 11:25:44 -0800
    • Engine revision 74d16627b9
    • Dart version 3.2.0
    • DevTools version 2.28.2

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio Giraffe.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[!] Android Studio (version unknown)
    • Android Studio at /Applications/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build 17.0.8+0-17.0.8b1000.22-10799086)

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • android-studio-dir = /Applications/Android Studio.app/
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0

[✓] Connected device (3 available)
    • RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64  • Android 11 (API 30)
    • macOS (desktop)  • macos            • darwin-x64     • macOS 14.1 23B74 darwin-x64
    • Chrome (web)     • chrome           • web-javascript • Google Chrome 119.0.6045.123

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.
[!] Flutter (Channel master, 3.17.0-15.0.pre.28, on macOS 14.1 23B74 darwin-x64, locale en-VN)
    • Flutter version 3.17.0-15.0.pre.28 on channel master at /Users/huynq/Documents/GitHub/flutter_master
    ! Warning: `flutter` on your path resolves to /Users/huynq/Documents/GitHub/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/huynq/Documents/GitHub/flutter_master. Consider adding /Users/huynq/Documents/GitHub/flutter_master/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/huynq/Documents/GitHub/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/huynq/Documents/GitHub/flutter_master. Consider adding /Users/huynq/Documents/GitHub/flutter_master/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2949638e82 (2 hours ago), 2023-11-26 19:35:25 -0500
    • Engine revision ebebb25aaa
    • Dart version 3.3.0 (build 3.3.0-152.0.dev)
    • DevTools version 2.30.0-dev.4
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/huynq/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/huynq/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version unknown)
    • Android Studio at /Applications/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build 17.0.8+0-17.0.8b1000.22-10799086)

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio Giraffe Patch 3.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • android-studio-dir = /Applications/Android Studio.app/
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0

[✓] Connected device (3 available)
    • RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64  • Android 11 (API 30)
    • macOS (desktop)  • macos            • darwin-x64     • macOS 14.1 23B74 darwin-x64
    • Chrome (web)     • chrome           • web-javascript • Google Chrome 119.0.6045.159
    ! Error: iPhone has recently restarted. Xcode will continue when iPhone is unlocked. (code -14)

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.

@huycozy huycozy added framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. a: error message Error messages from the Flutter framework has reproducible steps The issue has been confirmed reproducible and is ready to work on team-design Owned by Design Languages team found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 and removed in triage Presently being triaged by the triage team labels Nov 27, 2023
@HansMuller HansMuller self-assigned this Nov 29, 2023
@HansMuller HansMuller added P2 Important issues not at the top of the work list triaged-design Triaged by Design Languages team labels Nov 29, 2023
@HansMuller HansMuller removed their assignment Jan 25, 2024
@TahaTesser TahaTesser changed the title MaterialStateController with disabled button causes Exception Calling setState in a MaterialStatesController listener and MaterialStateController.update causes Exception Feb 14, 2024
@TahaTesser TahaTesser self-assigned this Feb 14, 2024
@github-project-automation github-project-automation bot moved this to To do in Nevercode Feb 14, 2024
@TahaTesser TahaTesser moved this from To do to In progress in Nevercode Feb 14, 2024
@TahaTesser TahaTesser moved this from In progress to PR submitted in Nevercode Feb 14, 2024
@TahaTesser TahaTesser added the d: api docs Issues with https://api.flutter.dev/ label Feb 16, 2024
auto-submit bot pushed a commit that referenced this issue Feb 16, 2024
…stener (#143453)

fixes [Calling `setState` in a `MaterialStatesController` listener and `MaterialStateController.update` causes Exception](#138986)

### Description
`MaterialStatesController` listener  calls `setState` during build when `MaterialStatesController.update` listener calls `notifyListeners`.

I tried fixing this issue by putting `notifyListeners` in a post-frame callback. However, this breaks existing customer tests (particularly super editor tests).

A safer approach would be to document that the listener's `setState` call should be in a post-frame callback to delay it and not call this during the build phase triggered by the `MaterialStatesController.update` in the widgets such as InkWell or buttons.
@github-project-automation github-project-automation bot moved this from PR submitted to Done (PR merged) in Nevercode Feb 16, 2024
@TahaTesser TahaTesser added the r: fixed Issue is closed as already fixed in a newer version label Feb 16, 2024
Copy link

github-actions bot commented Mar 1, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: error message Error messages from the Flutter framework d: api docs Issues with https://api.flutter.dev/ f: material design flutter/packages/flutter/material repository. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list r: fixed Issue is closed as already fixed in a newer version team-design Owned by Design Languages team triaged-design Triaged by Design Languages team
Projects
Status: Done (PR merged)
Development

Successfully merging a pull request may close this issue.

4 participants