Unverified Commit 703d60b5 authored by Polina Cherkasova's avatar Polina Cherkasova Committed by GitHub

FocusNode and FocusManager should dispatch creation in constructor. (#133352)

parent cf91262f
...@@ -471,6 +471,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -471,6 +471,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
void dispose() { void dispose() {
_historyEntry?.remove(); _historyEntry?.remove();
_controller.dispose(); _controller.dispose();
_focusScopeNode.dispose();
super.dispose(); super.dispose();
} }
......
...@@ -437,6 +437,10 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { ...@@ -437,6 +437,10 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
_descendantsAreTraversable = descendantsAreTraversable { _descendantsAreTraversable = descendantsAreTraversable {
// Set it via the setter so that it does nothing on release builds. // Set it via the setter so that it does nothing on release builds.
this.debugLabel = debugLabel; this.debugLabel = debugLabel;
if (kFlutterMemoryAllocationsEnabled) {
maybeDispatchObjectCreation();
}
} }
/// If true, tells the focus traversal policy to skip over this node for /// If true, tells the focus traversal policy to skip over this node for
...@@ -1463,6 +1467,9 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { ...@@ -1463,6 +1467,9 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
/// handlers, callers must call [registerGlobalHandlers]. See the /// handlers, callers must call [registerGlobalHandlers]. See the
/// documentation in that method for caveats to watch out for. /// documentation in that method for caveats to watch out for.
FocusManager() { FocusManager() {
if (kFlutterMemoryAllocationsEnabled) {
maybeDispatchObjectCreation();
}
rootScope._manager = this; rootScope._manager = this;
} }
......
...@@ -1609,6 +1609,41 @@ void main() { ...@@ -1609,6 +1609,41 @@ void main() {
tester.binding.focusManager.removeListener(handleFocusChange); tester.binding.focusManager.removeListener(handleFocusChange);
}); });
test('$FocusManager dispatches object creation in constructor', () {
final List<ObjectEvent> events = <ObjectEvent>[];
void listener(ObjectEvent event) {
if (event.object.runtimeType == FocusManager) {
events.add(event);
}
}
MemoryAllocations.instance.addListener(listener);
final FocusManager focusManager = FocusManager();
expect(events, hasLength(1));
focusManager.dispose();
MemoryAllocations.instance.removeListener(listener);
});
test('$FocusNode dispatches object creation in constructor', () {
final List<ObjectEvent> events = <ObjectEvent>[];
void listener(ObjectEvent event) {
if (event.object.runtimeType == FocusNode) {
events.add(event);
}
}
MemoryAllocations.instance.addListener(listener);
final FocusNode focusManager = FocusNode();
expect(events, hasLength(1));
focusManager.dispose();
MemoryAllocations.instance.removeListener(listener);
});
testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async {
final FocusNode nodeA = FocusNode(debugLabel: 'a'); final FocusNode nodeA = FocusNode(debugLabel: 'a');
final FocusNode nodeB = FocusNode(debugLabel: 'b'); final FocusNode nodeB = FocusNode(debugLabel: 'b');
......
...@@ -6,20 +6,26 @@ import 'package:flutter/foundation.dart'; ...@@ -6,20 +6,26 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
int _creations = 0;
int _disposals = 0;
void main() { void main() {
final MemoryAllocations ma = MemoryAllocations.instance; final MemoryAllocations ma = MemoryAllocations.instance;
setUp(() {
assert(!ma.hasListeners);
});
test('Publishers dispatch events in debug mode', () async { test('Publishers dispatch events in debug mode', () async {
int eventCount = 0; void listener(ObjectEvent event) {
void listener(ObjectEvent event) => eventCount++; if (event is ObjectDisposed) {
_disposals++;
}
if (event is ObjectCreated) {
_creations++;
}
}
ma.addListener(listener); ma.addListener(listener);
final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents(); final _EventStats actual = await _activateFlutterObjectsAndReturnCountOfEvents();
expect(eventCount, expectedEventCount); expect(actual.creations, _creations);
expect(actual.disposals, _disposals);
ma.removeListener(listener); ma.removeListener(listener);
expect(ma.hasListeners, isFalse); expect(ma.hasListeners, isFalse);
...@@ -29,6 +35,8 @@ void main() { ...@@ -29,6 +35,8 @@ void main() {
bool stateCreated = false; bool stateCreated = false;
bool stateDisposed = false; bool stateDisposed = false;
expect(ma.hasListeners, false);
void listener(ObjectEvent event) { void listener(ObjectEvent event) {
if (event is ObjectCreated && event.object is State) { if (event is ObjectCreated && event.object is State) {
stateCreated = true; stateCreated = true;
...@@ -47,7 +55,7 @@ void main() { ...@@ -47,7 +55,7 @@ void main() {
expect(stateCreated, isTrue); expect(stateCreated, isTrue);
expect(stateDisposed, isTrue); expect(stateDisposed, isTrue);
ma.removeListener(listener); ma.removeListener(listener);
expect(ma.hasListeners, isFalse); expect(ma.hasListeners, false);
}); });
} }
...@@ -62,7 +70,8 @@ class _TestElement extends RenderObjectElement with RootElementMixin { ...@@ -62,7 +70,8 @@ class _TestElement extends RenderObjectElement with RootElementMixin {
_TestElement(): super(_TestLeafRenderObjectWidget()); _TestElement(): super(_TestLeafRenderObjectWidget());
void makeInactive() { void makeInactive() {
assignOwner(BuildOwner(focusManager: FocusManager())); final FocusManager newFocusManager = FocusManager();
assignOwner(BuildOwner(focusManager: newFocusManager));
mount(null, null); mount(null, null);
deactivate(); deactivate();
} }
...@@ -109,15 +118,22 @@ class _TestStatefulWidgetState extends State<_TestStatefulWidget> { ...@@ -109,15 +118,22 @@ class _TestStatefulWidgetState extends State<_TestStatefulWidget> {
} }
} }
class _EventStats {
int creations = 0;
int disposals = 0;
}
/// Create and dispose Flutter objects to fire memory allocation events. /// Create and dispose Flutter objects to fire memory allocation events.
Future<int> _activateFlutterObjectsAndReturnCountOfEvents() async { Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async {
int count = 0; final _EventStats result = _EventStats();
final _TestElement element = _TestElement(); count++; final _TestElement element = _TestElement(); result.creations++;
final RenderObject renderObject = _TestRenderObject(); count++; final RenderObject renderObject = _TestRenderObject(); result.creations++;
element.makeInactive(); element.unmount(); count += 3; element.makeInactive(); result.creations += 3; // 1 for the new BuildOwner, 1 for the new FocusManager, 1 for the new FocusScopeNode
renderObject.dispose(); count++; element.unmount(); result.disposals += 2; // 1 for the old BuildOwner, 1 for the element
renderObject.dispose(); result.disposals += 1;
return count; return result;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment