FocusNode and FocusManager should dispatch creation in constructor. (#133352)
This commit is contained in:
parent
cf91262f75
commit
703d60b5e9
@ -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 {
|
|||||||
_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 {
|
|||||||
/// 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() {
|
|||||||
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';
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 {
|
|||||||
_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> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
|
||||||
Future<int> _activateFlutterObjectsAndReturnCountOfEvents() async {
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
final _TestElement element = _TestElement(); count++;
|
class _EventStats {
|
||||||
final RenderObject renderObject = _TestRenderObject(); count++;
|
int creations = 0;
|
||||||
|
int disposals = 0;
|
||||||
element.makeInactive(); element.unmount(); count += 3;
|
}
|
||||||
renderObject.dispose(); count++;
|
|
||||||
|
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||||
return count;
|
Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async {
|
||||||
|
final _EventStats result = _EventStats();
|
||||||
|
|
||||||
|
final _TestElement element = _TestElement(); result.creations++;
|
||||||
|
final RenderObject renderObject = _TestRenderObject(); result.creations++;
|
||||||
|
|
||||||
|
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 result;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user