From 0903cb5fefab2241242e7a4eaaf74ff4fa51bc44 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 19 Jan 2016 09:56:52 -0800 Subject: [PATCH] Refactor Inherited to avoid all the tree walks during build. --- .../flutter/lib/src/widgets/framework.dart | 69 +++++++++++-------- .../flutter/lib/src/widgets/locale_query.dart | 2 +- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 7f44b94724..3ebc4198a4 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -566,20 +566,12 @@ class _InactiveElements { _elements.add(element); } - void _reactivate(Element element) { - assert(element._debugLifecycleState == _ElementLifecycle.inactive); - element.reactivate(); - assert(element._debugLifecycleState == _ElementLifecycle.active); - element.visitChildren(_reactivate); - } - void remove(Element element) { assert(!_locked); assert(_elements.contains(element)); assert(element._parent == null); _elements.remove(element); assert(!element._active); - _reactivate(element); } } @@ -729,6 +721,7 @@ abstract class Element implements BuildContext { final GlobalKey key = widget.key; key._register(this); } + _updateInheritance(); assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; }); } @@ -793,7 +786,7 @@ abstract class Element implements BuildContext { _slot = newSlot; } - Element _findAndActivateElement(GlobalKey key, Widget newWidget) { + Element _retakeInactiveElement(GlobalKey key, Widget newWidget) { Element element = key._currentElement; if (element == null) return null; @@ -809,13 +802,11 @@ abstract class Element implements BuildContext { Element _inflateWidget(Widget newWidget, dynamic newSlot) { Key key = newWidget.key; if (key is GlobalKey) { - Element newChild = _findAndActivateElement(key, newWidget); + Element newChild = _retakeInactiveElement(key, newWidget); if (newChild != null) { assert(newChild._parent == null); assert(() { _debugCheckForCycles(newChild); return true; }); - newChild._parent = this; - newChild._updateDepth(); - newChild.attachRenderObject(newSlot); + newChild.activate(this, newSlot); Element updatedChild = updateChild(newChild, newWidget, newSlot); assert(newChild == updatedChild); return updatedChild; @@ -847,6 +838,26 @@ abstract class Element implements BuildContext { _inactiveElements.add(child); // this eventually calls child.deactivate() } + void activate(Element parent, dynamic newSlot) { + assert(_debugLifecycleState == _ElementLifecycle.inactive); + _reactivate(); + _parent = parent; + _updateDepth(); + _updateInheritance(); + attachRenderObject(newSlot); + assert(_debugLifecycleState == _ElementLifecycle.active); + } + + void _reactivate() { + assert(_debugLifecycleState == _ElementLifecycle.inactive); + assert(widget != null); + assert(depth != null); + assert(!_active); + _active = true; + assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; }); + visitChildren((Element child) => child._reactivate()); + } + void deactivate() { assert(_debugLifecycleState == _ElementLifecycle.active); assert(widget != null); @@ -866,15 +877,6 @@ abstract class Element implements BuildContext { assert(_debugLifecycleState == _ElementLifecycle.inactive); } - void reactivate() { - assert(_debugLifecycleState == _ElementLifecycle.inactive); - assert(widget != null); - assert(depth != null); - assert(!_active); - _active = true; - assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; }); - } - /// Called when an Element is removed from the tree permanently. void unmount() { assert(_debugLifecycleState == _ElementLifecycle.inactive); @@ -890,22 +892,24 @@ abstract class Element implements BuildContext { RenderObject findRenderObject() => renderObject; + Map _inheritedWidgets; Set _dependencies; InheritedWidget inheritFromWidgetOfExactType(Type targetType) { - Element ancestor = _parent; - while (ancestor != null && ancestor.widget.runtimeType != targetType) - ancestor = ancestor._parent; + InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType]; if (ancestor != null) { assert(ancestor is InheritedElement); _dependencies ??= new HashSet(); _dependencies.add(ancestor); - InheritedElement typedAncestor = ancestor; - typedAncestor._dependants.add(this); + ancestor._dependants.add(this); return ancestor.widget; } return null; } + void _updateInheritance() { + _inheritedWidgets = _parent?._inheritedWidgets; + } + Widget ancestorWidgetOfExactType(Type targetType) { Element ancestor = _parent; while (ancestor != null && ancestor.widget.runtimeType != targetType) @@ -1378,7 +1382,16 @@ class ParentDataElement extends _ProxyElement { class InheritedElement extends _ProxyElement { InheritedElement(InheritedWidget widget) : super(widget); - Set _dependants = new HashSet(); + final Set _dependants = new HashSet(); + + void _updateInheritance() { + final Map incomingWidgets = _parent?._inheritedWidgets; + if (incomingWidgets != null) + _inheritedWidgets = new Map.from(incomingWidgets); + else + _inheritedWidgets = new Map(); + _inheritedWidgets[widget.runtimeType] = this; + } void debugDeactivated() { assert(() { diff --git a/packages/flutter/lib/src/widgets/locale_query.dart b/packages/flutter/lib/src/widgets/locale_query.dart index bba7021207..f6980bda50 100644 --- a/packages/flutter/lib/src/widgets/locale_query.dart +++ b/packages/flutter/lib/src/widgets/locale_query.dart @@ -21,7 +21,7 @@ class LocaleQuery extends InheritedWidget { /// The data from the closest instance of this class that encloses the given context. static LocaleQueryData of(BuildContext context) { LocaleQuery query = context.inheritFromWidgetOfExactType(LocaleQuery); - return query == null ? null : query.data; + return query?.data; } bool updateShouldNotify(LocaleQuery old) => data != old.data;