Merge BuildableElement and Element (#8758)
There aren't any subclasses of Element that don't also subclass
BuildableElement and I suspect they wouldn't work properly anyway.
Fixes #3656
diff --git a/dev/benchmarks/microbenchmarks/lib/stocks/build_bench.dart b/dev/benchmarks/microbenchmarks/lib/stocks/build_bench.dart
index 37f6474..f3ca937 100644
--- a/dev/benchmarks/microbenchmarks/lib/stocks/build_bench.dart
+++ b/dev/benchmarks/microbenchmarks/lib/stocks/build_bench.dart
@@ -35,7 +35,7 @@
await tester.pump(); // Start drawer animation
await tester.pump(const Duration(seconds: 1)); // Complete drawer animation
- final BuildableElement appState = tester.element(find.byType(stocks.StocksApp));
+ final Element appState = tester.element(find.byType(stocks.StocksApp));
watch.start();
while (watch.elapsed < kBenchmarkTime) {
diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart
index 4fb3031..867d98b 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -1700,13 +1700,13 @@
final _InactiveElements _inactiveElements = new _InactiveElements();
- final List<BuildableElement> _dirtyElements = <BuildableElement>[];
+ final List<Element> _dirtyElements = <Element>[];
bool _scheduledFlushDirtyElements = false;
bool _dirtyElementsNeedsResorting; // null means we're not in a buildScope
/// Adds an element to the dirty elements list so that it will be rebuilt
/// when [WidgetsBinding.beginFrame] calls [buildScope].
- void scheduleBuildFor(BuildableElement element) {
+ void scheduleBuildFor(Element element) {
assert(element != null);
assert(element.owner == this);
assert(() {
@@ -1758,7 +1758,7 @@
int _debugStateLockLevel = 0;
bool get _debugStateLocked => _debugStateLockLevel > 0;
bool _debugBuilding = false;
- BuildableElement _debugCurrentBuildTarget;
+ Element _debugCurrentBuildTarget;
/// Establishes a scope in which calls to [State.setState] are forbidden, and
/// calls the given `callback`.
@@ -1803,7 +1803,7 @@
/// Only one [buildScope] can be active at a time.
///
/// A [buildScope] implies a [lockState] scope as well.
- void buildScope(BuildableElement context, [VoidCallback callback]) {
+ void buildScope(Element context, [VoidCallback callback]) {
if (callback == null && _dirtyElements.isEmpty)
return;
assert(context != null);
@@ -1820,9 +1820,8 @@
try {
_scheduledFlushDirtyElements = true;
if (callback != null) {
- assert(context is BuildableElement);
assert(_debugStateLocked);
- BuildableElement debugPreviousBuildTarget;
+ Element debugPreviousBuildTarget;
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
debugPreviousBuildTarget = _debugCurrentBuildTarget;
@@ -1879,7 +1878,7 @@
}
}
assert(() {
- if (_dirtyElements.any((BuildableElement element) => element._active && element.dirty)) {
+ if (_dirtyElements.any((Element element) => element._active && element.dirty)) {
throw new FlutterError(
'buildScope missed some dirty elements.\n'
'This probably indicates that the dirty list should have been resorted but was not.\n'
@@ -1890,7 +1889,7 @@
return true;
});
} finally {
- for (BuildableElement element in _dirtyElements) {
+ for (Element element in _dirtyElements) {
assert(element._inDirtyList);
element._inDirtyList = false;
}
@@ -2115,9 +2114,6 @@
int get depth => _depth;
int _depth;
- /// Returns true if the element has been marked as needing rebuilding.
- bool get dirty => false;
-
static int _sort(Element a, Element b) {
if (a.depth < b.depth)
return -1;
@@ -2141,7 +2137,9 @@
bool _active = false;
+ @mustCallSuper
void _reassemble() {
+ markNeedsBuild();
visitChildren((Element child) {
child._reassemble();
});
@@ -2554,6 +2552,7 @@
assert(owner != null);
assert(depth != null);
assert(!_active);
+ final bool hadDependencies = ((_dependencies != null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies);
_active = true;
// We unregistered our dependencies in deactivate, but never cleared the list.
// Since we're going to be reused, let's clear our list now.
@@ -2561,6 +2560,12 @@
_hadUnsatisfiedDependencies = false;
_updateInheritance();
assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
+ if (_dirty)
+ owner.scheduleBuildFor(this);
+ if (hadDependencies)
+ didChangeDependencies
+
+ ();
}
/// Transition from the "active" to the "inactive" lifecycle state.
@@ -2587,9 +2592,9 @@
// For expediency, we don't actually clear the list here, even though it's
// no longer representative of what we are registered with. If we never
// get re-used, it doesn't matter. If we do, then we'll clear the list in
- // activate(). The benefit of this is that it allows BuildableElement's
- // activate() implementation to decide whether to rebuild based on whether
- // we had dependencies here.
+ // activate(). The benefit of this is that it allows Element's activate()
+ // implementation to decide whether to rebuild based on whether we had
+ // dependencies here.
}
_inheritedWidgets = null;
_active = false;
@@ -2787,7 +2792,10 @@
/// [InheritedWidget.updateShouldNotify] returned true), the framework calls
/// this function to notify this element of the change.
@mustCallSuper
- void didChangeDependencies() { }
+ void didChangeDependencies() {
+ assert(_active); // otherwise markNeedsBuild is a no-op
+ markNeedsBuild();
+ }
/// Returns a description of what caused this element to be created.
///
@@ -2838,6 +2846,8 @@
description.add('${widget.key}');
widget.debugFillDescription(description);
}
+ if (dirty)
+ description.add('dirty');
}
/// A detailed, textual description of this element, includings its children.
@@ -2853,50 +2863,8 @@
}
return result;
}
-}
-
-/// A widget that renders an exception's message.
-///
-/// This widget is used when a build function fails, to help with determining
-/// where the problem lies. Exceptions are also logged to the console, which you
-/// can read using `flutter logs`. The console will also include additional
-/// information such as the stack trace for the exception.
-class ErrorWidget extends LeafRenderObjectWidget {
- /// Creates a widget that displays the given error message.
- ErrorWidget(Object exception) : message = _stringify(exception),
- super(key: new UniqueKey());
-
- /// The message to display.
- final String message;
-
- static String _stringify(Object exception) {
- try {
- return exception.toString();
- } catch (e) { }
- return 'Error';
- }
-
- @override
- RenderBox createRenderObject(BuildContext context) => new RenderErrorBox(message);
-
- @override
- void debugFillDescription(List<String> description) {
- super.debugFillDescription(description);
- description.add('message: ' + _stringify(message));
- }
-}
-
-/// An [Element] that can be marked dirty and rebuilt.
-///
-/// In practice, all subclasses of [Element] in the Flutter framework are
-/// subclasses of [BuildableElement]. The distinction exists primarily to
-/// segregate unrelated code.
-abstract class BuildableElement extends Element {
- /// Creates an element that uses the given widget as its configuration.
- BuildableElement(Widget widget) : super(widget);
/// Returns true if the element has been marked as needing rebuilding.
- @override
bool get dirty => _dirty;
bool _dirty = true;
@@ -2991,7 +2959,7 @@
});
assert(_debugLifecycleState == _ElementLifecycle.active);
assert(owner._debugStateLocked);
- BuildableElement debugPreviousBuildTarget;
+ Element debugPreviousBuildTarget;
assert(() {
debugPreviousBuildTarget = owner._debugCurrentBuildTarget;
owner._debugCurrentBuildTarget = this;
@@ -3009,35 +2977,36 @@
/// Called by rebuild() after the appropriate checks have been made.
@protected
void performRebuild();
+}
- @override
- void didChangeDependencies() {
- super.didChangeDependencies();
- assert(_active); // otherwise markNeedsBuild is a no-op
- markNeedsBuild();
+/// A widget that renders an exception's message.
+///
+/// This widget is used when a build function fails, to help with determining
+/// where the problem lies. Exceptions are also logged to the console, which you
+/// can read using `flutter logs`. The console will also include additional
+/// information such as the stack trace for the exception.
+class ErrorWidget extends LeafRenderObjectWidget {
+ /// Creates a widget that displays the given error message.
+ ErrorWidget(Object exception) : message = _stringify(exception),
+ super(key: new UniqueKey());
+
+ /// The message to display.
+ final String message;
+
+ static String _stringify(Object exception) {
+ try {
+ return exception.toString();
+ } catch (e) { }
+ return 'Error';
}
@override
- void activate() {
- final bool hadDependencies = ((_dependencies != null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies);
- super.activate(); // clears _dependencies, and sets active to true
- if (_dirty)
- owner.scheduleBuildFor(this);
- if (hadDependencies)
- didChangeDependencies();
- }
-
- @override
- void _reassemble() {
- markNeedsBuild();
- super._reassemble();
- }
+ RenderBox createRenderObject(BuildContext context) => new RenderErrorBox(message);
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
- if (dirty)
- description.add('dirty');
+ description.add('message: ' + _stringify(message));
}
}
@@ -3059,7 +3028,7 @@
/// [RenderObject]s indirectly by creating other [Element]s.
///
/// Contrast with [RenderObjectElement].
-abstract class ComponentElement extends BuildableElement {
+abstract class ComponentElement extends Element {
/// Creates an element that uses the given widget as its configuration.
ComponentElement(Widget widget) : super(widget);
@@ -3630,7 +3599,7 @@
/// expose them in its implementation of the [visitChildren] method. This method
/// is used by many of the framework's internal mechanisms, and so should be
/// fast. It is also used by the test framework and [debugDumpApp].
-abstract class RenderObjectElement extends BuildableElement {
+abstract class RenderObjectElement extends Element {
/// Creates an element that uses the given widget as its configuration.
RenderObjectElement(RenderObjectWidget widget) : super(widget);