markNeedsBuild method

void markNeedsBuild ()

Marks the element as dirty and adds it to the global list of widgets to rebuild in the next frame.

Since it is inefficient to build an element twice in one frame, applications and widgets should be structured so as to only mark widgets dirty during event handlers before the frame begins, not during the build itself.

Implementation

void markNeedsBuild() {
  assert(_debugLifecycleState != _ElementLifecycle.defunct);
  if (!_active)
    return;
  assert(owner != null);
  assert(_debugLifecycleState == _ElementLifecycle.active);
  assert(() {
    if (owner._debugBuilding) {
      assert(owner._debugCurrentBuildTarget != null);
      assert(owner._debugStateLocked);
      if (_debugIsInScope(owner._debugCurrentBuildTarget))
        return true;
      if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
        final List<DiagnosticsNode> information = <DiagnosticsNode>[
          ErrorSummary('setState() or markNeedsBuild() called during build.'),
          ErrorDescription(
            'This ${widget.runtimeType} 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.'
          ),
          describeElement(
            'The widget on which setState() or markNeedsBuild() was called was',
          )
        ];
        if (owner._debugCurrentBuildTarget != null)
          information.add(owner._debugCurrentBuildTarget.describeWidget('The widget which was currently being built when the offending call was made was'));
        throw FlutterError.fromParts(information);
      }
      assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
    } else if (owner._debugStateLocked) {
      assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('setState() or markNeedsBuild() called when widget tree was locked.'),
        ErrorDescription(
          'This ${widget.runtimeType} widget cannot be marked as needing to build '
          'because the framework is locked.'
        ),
        describeElement('The widget on which setState() or markNeedsBuild() was called was')
      ]);
    }
    return true;
  }());
  if (dirty)
    return;
  _dirty = true;
  owner.scheduleBuildFor(this);
}