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
void dispose() {
_historyEntry?.remove();
_controller.dispose();
_focusScopeNode.dispose();
super.dispose();
}
......
......@@ -437,6 +437,10 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
_descendantsAreTraversable = descendantsAreTraversable {
// Set it via the setter so that it does nothing on release builds.
this.debugLabel = debugLabel;
if (kFlutterMemoryAllocationsEnabled) {
maybeDispatchObjectCreation();
}
}
/// If true, tells the focus traversal policy to skip over this node for
......@@ -1463,6 +1467,9 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
/// handlers, callers must call [registerGlobalHandlers]. See the
/// documentation in that method for caveats to watch out for.
FocusManager() {
if (kFlutterMemoryAllocationsEnabled) {
maybeDispatchObjectCreation();
}
rootScope._manager = this;
}
......
......@@ -1609,6 +1609,41 @@ void main() {
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 {
final FocusNode nodeA = FocusNode(debugLabel: 'a');
final FocusNode nodeB = FocusNode(debugLabel: 'b');
......
......@@ -6,20 +6,26 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
int _creations = 0;
int _disposals = 0;
void main() {
final MemoryAllocations ma = MemoryAllocations.instance;
setUp(() {
assert(!ma.hasListeners);
});
test('Publishers dispatch events in debug mode', () async {
int eventCount = 0;
void listener(ObjectEvent event) => eventCount++;
void listener(ObjectEvent event) {
if (event is ObjectDisposed) {
_disposals++;
}
if (event is ObjectCreated) {
_creations++;
}
}
ma.addListener(listener);
final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents();
expect(eventCount, expectedEventCount);
final _EventStats actual = await _activateFlutterObjectsAndReturnCountOfEvents();
expect(actual.creations, _creations);
expect(actual.disposals, _disposals);
ma.removeListener(listener);
expect(ma.hasListeners, isFalse);
......@@ -29,6 +35,8 @@ void main() {
bool stateCreated = false;
bool stateDisposed = false;
expect(ma.hasListeners, false);
void listener(ObjectEvent event) {
if (event is ObjectCreated && event.object is State) {
stateCreated = true;
......@@ -47,7 +55,7 @@ void main() {
expect(stateCreated, isTrue);
expect(stateDisposed, isTrue);
ma.removeListener(listener);
expect(ma.hasListeners, isFalse);
expect(ma.hasListeners, false);
});
}
......@@ -62,7 +70,8 @@ class _TestElement extends RenderObjectElement with RootElementMixin {
_TestElement(): super(_TestLeafRenderObjectWidget());
void makeInactive() {
assignOwner(BuildOwner(focusManager: FocusManager()));
final FocusManager newFocusManager = FocusManager();
assignOwner(BuildOwner(focusManager: newFocusManager));
mount(null, null);
deactivate();
}
......@@ -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.
Future<int> _activateFlutterObjectsAndReturnCountOfEvents() async {
int count = 0;
Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async {
final _EventStats result = _EventStats();
final _TestElement element = _TestElement(); count++;
final RenderObject renderObject = _TestRenderObject(); count++;
final _TestElement element = _TestElement(); result.creations++;
final RenderObject renderObject = _TestRenderObject(); result.creations++;
element.makeInactive(); element.unmount(); count += 3;
renderObject.dispose(); count++;
element.makeInactive(); result.creations += 3; // 1 for the new BuildOwner, 1 for the new FocusManager, 1 for the new FocusScopeNode
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