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

The error message when you show a snackbar during build is unintuitive #66789

Closed
Hixie opened this issue Sep 27, 2020 · 7 comments · Fixed by #106658
Closed

The error message when you show a snackbar during build is unintuitive #66789

Hixie opened this issue Sep 27, 2020 · 7 comments · Fixed by #106658
Assignees
Labels
a: error message Error messages from the Flutter framework a: quality A truly polished experience framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project r: fixed Issue is closed as already fixed in a newer version

Comments

@Hixie
Copy link
Contributor

Hixie commented Sep 27, 2020

We should catch it explicitly in the scaffold code and say something like "Snackbars cannot be shown during build" or some such.

I/flutter (30702): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (30702): The following assertion was thrown building _BodyBuilder:
I/flutter (30702): setState() or markNeedsBuild() called during build.
I/flutter (30702): This Scaffold widget cannot be marked as needing to build because the framework is already in the
I/flutter (30702): process of building widgets.  A widget can be marked as needing to be built during the build phase
I/flutter (30702): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter (30702): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter (30702): Otherwise, the framework might not visit this widget during this build phase.
I/flutter (30702): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (30702):   Scaffold
I/flutter (30702): The widget which was currently being built when the offending call was made was:
I/flutter (30702):   _BodyBuilder
I/flutter (30702): 
I/flutter (30702): The relevant error-causing widget was:
I/flutter (30702):   Scaffold file:///home/ianh/dev/ant/lib/main.dart:12:11
I/flutter (30702): 
I/flutter (30702): When the exception was thrown, this was the stack:
I/flutter (30702): #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4284:11)
I/flutter (30702): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4299:6)
I/flutter (30702): #2      State.setState (package:flutter/src/widgets/framework.dart:1275:15)
I/flutter (30702): #3      ScaffoldState.showSnackBar (package:flutter/src/material/scaffold.dart:1731:5)
I/flutter (30702): #4      _BoardViewState.showMessage (package:ant/main.dart:207:26)
I/flutter (30702): #5      _BoardViewState._toggle (package:ant/main.dart:202:7)
I/flutter (30702): #6      _BoardViewState.initState (package:ant/main.dart:162:5)
I/flutter (30702): #7      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4778:57)
I/flutter (30702): #8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4615:5)
I/flutter (30702): ...     Normal element mounting (19 frames)
I/flutter (30702): #27     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3581:14)
I/flutter (30702): #28     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6248:32)
I/flutter (30702): ...     Normal element mounting (202 frames)
I/flutter (30702): #230    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3581:14)
I/flutter (30702): #231    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6248:32)
I/flutter (30702): ...     Normal element mounting (267 frames)
I/flutter (30702): #498    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3581:14)
I/flutter (30702): #499    Element.updateChild (package:flutter/src/widgets/framework.dart:3346:18)
I/flutter (30702): #500    RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1215:16)
I/flutter (30702): #501    RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1186:5)
I/flutter (30702): #502    RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1128:18)
I/flutter (30702): #503    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2696:19)
I/flutter (30702): #504    RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1127:13)
I/flutter (30702): #505    WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:967:7)
I/flutter (30702): #506    WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:948:7)
I/flutter (30702): (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (30702): 
I/flutter (30702): ════════════════════════════════════════════════════════════════════════════════════════════════════
@Hixie Hixie added easy fix framework flutter/packages/flutter repository. See also f: labels. a: quality A truly polished experience a: error message Error messages from the Flutter framework P3 Issues that are less important to the Flutter project labels Sep 27, 2020
@pedromassangocode
Copy link

A reproducible code sample would help.

@goderbauer
Copy link
Member

/cc @Piinks

@chinmoy12c
Copy link
Member

chinmoy12c commented Oct 1, 2020

Is this change required only for the snackbar widget or for the entire general error message?

@creativecreatorormaybenot
Copy link
Contributor

@Hixie I gave it a shot in a PR here: #88925

The tests pass, so it works. How intuitive my wording is - I am not sure; maybe it can be improved with a review, but I do think it is already a lot more helpful than the generic message 👍

@Ciock
Copy link

Ciock commented Dec 22, 2021

I tried a different approach scheduling a PostFrameCallback for the Snackbar if the framework is building, like it's done for the overlay:

if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
overlay._markDirty();
});
} else {
overlay._markDirty();
}

What I've done in showSnackBar():

if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks){
  SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
    if (mounted) {
      setState(() {
        _snackBars.addLast(controller);
      });
      _updateScaffolds();
    }
  });
} else {
  if (mounted) {
    setState(() {
      _snackBars.addLast(controller);
    });
    _updateScaffolds();
  }
}

The issue here is that the schedulerPhase is idle when the app is launched so setState is called during build, and I don't know why it isn't set as persistentCallbacks when first frame it's still to be rendered.

Here's my example code:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        body: Builder(builder: (context) {
          ScaffoldMessenger.of(context)
              .showSnackBar(const SnackBar(content: Text('Snack bar')));
          return Center(
            child: TextButton(
              onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('Snack bar by tap'))),
              child: const Text('Show SnackBar'),
            ),
          );
        }),
      ),
    );
  }
}

@Ciock
Copy link

Ciock commented Dec 27, 2021

Always scheduling the SnackBar in a post frame callback works, but I don't know if it impact the framework in any other ways.

@bleroux bleroux self-assigned this Jun 27, 2022
@bleroux bleroux added the r: fixed Issue is closed as already fixed in a newer version label Jul 1, 2022
@bleroux bleroux closed this as completed Jul 1, 2022
@github-actions
Copy link

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 Jul 15, 2022
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 a: quality A truly polished experience framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project r: fixed Issue is closed as already fixed in a newer version
Projects
Status: Done (PR merged)
7 participants