mirror of
https://github.com/flutter/flutter
synced 2024-10-12 11:12:54 +00:00
Made Directionality forego dependency tracking for better performance. (#102336)
This commit is contained in:
parent
1c80e29b8e
commit
18713e0c5d
|
@ -80,12 +80,69 @@ export 'package:flutter/services.dart' show
|
|||
|
||||
// BIDIRECTIONAL TEXT SUPPORT
|
||||
|
||||
/// An [InheritedElement] that has hundreds of dependencies but will
|
||||
/// infrequently change. This provides a performance tradeoff where building
|
||||
/// the [Widget]s is faster but performing updates is slower.
|
||||
///
|
||||
/// | | _UbiquitiousInheritedElement | InheritedElement |
|
||||
/// |---------------------|------------------------------|------------------|
|
||||
/// | insert (best case) | O(1) | O(1) |
|
||||
/// | insert (worst case) | O(1) | O(n) |
|
||||
/// | search (best case) | O(n) | O(1) |
|
||||
/// | search (worst case) | O(n) | O(n) |
|
||||
///
|
||||
/// Insert happens when building the [Widget] tree, search happens when updating
|
||||
/// [Widget]s.
|
||||
class _UbiquitousInheritedElement extends InheritedElement {
|
||||
/// Creates an element that uses the given widget as its configuration.
|
||||
_UbiquitousInheritedElement(super.widget);
|
||||
|
||||
@override
|
||||
void setDependencies(Element dependent, Object? value) {
|
||||
// This is where the cost of [InheritedElement] is incurred during build
|
||||
// time of the widget tree. Omitting this bookkeeping is where the
|
||||
// performance savings come from.
|
||||
assert(value == null);
|
||||
}
|
||||
|
||||
@override
|
||||
Object? getDependencies(Element dependent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void notifyClients(InheritedWidget oldWidget) {
|
||||
_recurseChildren(this, (Element element) {
|
||||
if (element.doesDependOnInheritedElement(this)) {
|
||||
notifyDependent(oldWidget, element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void _recurseChildren(Element element, ElementVisitor visitor) {
|
||||
element.visitChildren((Element child) {
|
||||
_recurseChildren(child, visitor);
|
||||
});
|
||||
visitor(element);
|
||||
}
|
||||
}
|
||||
|
||||
/// See also:
|
||||
///
|
||||
/// * [_UbiquitousInheritedElement], the [Element] for [_UbiquitousInheritedWidget].
|
||||
abstract class _UbiquitousInheritedWidget extends InheritedWidget {
|
||||
const _UbiquitousInheritedWidget({super.key, required super.child});
|
||||
|
||||
@override
|
||||
InheritedElement createElement() => _UbiquitousInheritedElement(this);
|
||||
}
|
||||
|
||||
/// A widget that determines the ambient directionality of text and
|
||||
/// text-direction-sensitive render objects.
|
||||
///
|
||||
/// For example, [Padding] depends on the [Directionality] to resolve
|
||||
/// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects.
|
||||
class Directionality extends InheritedWidget {
|
||||
class Directionality extends _UbiquitousInheritedWidget {
|
||||
/// Creates a widget that determines the directionality of text and
|
||||
/// text-direction-sensitive render objects.
|
||||
///
|
||||
|
|
|
@ -4197,6 +4197,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Returns `true` if [dependOnInheritedElement] was previously called with [ancestor].
|
||||
@protected
|
||||
bool doesDependOnInheritedElement(InheritedElement ancestor) =>
|
||||
_dependencies != null && _dependencies!.contains(ancestor);
|
||||
|
||||
@override
|
||||
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
|
||||
assert(ancestor != null);
|
||||
|
|
|
@ -1694,6 +1694,30 @@ The findRenderObject() method was called for the following element:
|
|||
|
||||
expect(inheritedElement.hashCode, identityHashCode(inheritedElement));
|
||||
});
|
||||
|
||||
testWidgets('doesDependOnInheritedElement', (WidgetTester tester) async {
|
||||
final _TestInheritedElement ancestor =
|
||||
_TestInheritedElement(const Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Placeholder(),
|
||||
));
|
||||
final _TestInheritedElement child =
|
||||
_TestInheritedElement(const Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Placeholder(),
|
||||
));
|
||||
expect(child.doesDependOnInheritedElement(ancestor), isFalse);
|
||||
child.dependOnInheritedElement(ancestor);
|
||||
expect(child.doesDependOnInheritedElement(ancestor), isTrue);
|
||||
});
|
||||
}
|
||||
|
||||
class _TestInheritedElement extends InheritedElement {
|
||||
_TestInheritedElement(super.widget);
|
||||
@override
|
||||
bool doesDependOnInheritedElement(InheritedElement element) {
|
||||
return super.doesDependOnInheritedElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
class _WidgetWithNoVisitChildren extends StatelessWidget {
|
||||
|
|
Loading…
Reference in a new issue