Instrument State, Layer, RenderObject and Element. (#111328)
This commit is contained in:
parent
6e491d8870
commit
0a35cf95eb
@ -215,11 +215,11 @@ class ChangeNotifier implements Listenable {
|
||||
void addListener(VoidCallback listener) {
|
||||
assert(ChangeNotifier.debugAssertNotDisposed(this));
|
||||
if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) {
|
||||
MemoryAllocations.instance.dispatchObjectEvent(ObjectCreated(
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterFoundationLibrary,
|
||||
className: 'ChangeNotifier',
|
||||
className: '$ChangeNotifier',
|
||||
object: this,
|
||||
));
|
||||
);
|
||||
_creationDispatched = true;
|
||||
}
|
||||
if (_count == _listeners.length) {
|
||||
@ -326,7 +326,7 @@ class ChangeNotifier implements Listenable {
|
||||
return true;
|
||||
}());
|
||||
if (kFlutterMemoryAllocationsEnabled && _creationDispatched) {
|
||||
MemoryAllocations.instance.dispatchObjectEvent(ObjectDisposed(object: this));
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
_listeners = _emptyListeners;
|
||||
_count = 0;
|
||||
@ -464,11 +464,11 @@ class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
|
||||
/// Creates a [ChangeNotifier] that wraps this value.
|
||||
ValueNotifier(this._value) {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectEvent(ObjectCreated(
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterFoundationLibrary,
|
||||
className: 'ValueNotifier',
|
||||
className: '$ValueNotifier',
|
||||
object: this,
|
||||
));
|
||||
);
|
||||
}
|
||||
_creationDispatched = true;
|
||||
}
|
||||
|
@ -258,6 +258,34 @@ class MemoryAllocations {
|
||||
_tryDefragmentListeners();
|
||||
}
|
||||
|
||||
/// Create [ObjectCreated] and invoke [dispatchObjectEvent] if there are listeners.
|
||||
///
|
||||
/// This method is more efficient than [dispatchObjectEvent] if the event object is not created yet.
|
||||
void dispatchObjectCreated({
|
||||
required String library,
|
||||
required String className,
|
||||
required Object object,
|
||||
}) {
|
||||
if (!hasListeners) {
|
||||
return;
|
||||
}
|
||||
dispatchObjectEvent(ObjectCreated(
|
||||
library: library,
|
||||
className: className,
|
||||
object: object,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create [ObjectDisposed] and invoke [dispatchObjectEvent] if there are listeners.
|
||||
///
|
||||
/// This method is more efficient than [dispatchObjectEvent] if the event object is not created yet.
|
||||
void dispatchObjectDisposed({required Object object}) {
|
||||
if (!hasListeners) {
|
||||
return;
|
||||
}
|
||||
dispatchObjectEvent(ObjectDisposed(object: object));
|
||||
}
|
||||
|
||||
void _subscribeToSdkObjects() {
|
||||
assert(ui.Image.onCreate == null);
|
||||
assert(ui.Image.onDispose == null);
|
||||
@ -283,7 +311,7 @@ class MemoryAllocations {
|
||||
void _imageOnCreate(ui.Image image) {
|
||||
dispatchObjectEvent(ObjectCreated(
|
||||
library: _dartUiLibrary,
|
||||
className: 'Image',
|
||||
className: '${ui.Image}',
|
||||
object: image,
|
||||
));
|
||||
}
|
||||
@ -291,7 +319,7 @@ class MemoryAllocations {
|
||||
void _pictureOnCreate(ui.Picture picture) {
|
||||
dispatchObjectEvent(ObjectCreated(
|
||||
library: _dartUiLibrary,
|
||||
className: 'Picture',
|
||||
className: '${ui.Picture}',
|
||||
object: picture,
|
||||
));
|
||||
}
|
||||
|
@ -73,6 +73,8 @@ class AnnotationResult<T> {
|
||||
}
|
||||
}
|
||||
|
||||
const String _flutterRenderingLibrary = 'package:flutter/rendering.dart';
|
||||
|
||||
/// A composited layer.
|
||||
///
|
||||
/// During painting, the render tree generates a tree of composited layers that
|
||||
@ -135,6 +137,17 @@ class AnnotationResult<T> {
|
||||
/// * [RenderView.compositeFrame], which implements this recomposition protocol
|
||||
/// for painting [RenderObject] trees on the display.
|
||||
abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
||||
/// Creates an instance of Layer.
|
||||
Layer() {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterRenderingLibrary,
|
||||
className: '$Layer',
|
||||
object: this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final Map<int, VoidCallback> _callbacks = <int, VoidCallback>{};
|
||||
static int _nextCallbackId = 0;
|
||||
|
||||
@ -320,6 +333,9 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
||||
_debugDisposed = true;
|
||||
return true;
|
||||
}());
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
_engineLayer?.dispose();
|
||||
_engineLayer = null;
|
||||
}
|
||||
|
@ -1248,6 +1248,8 @@ class PipelineOwner {
|
||||
}
|
||||
}
|
||||
|
||||
const String _flutterRenderingLibrary = 'package:flutter/rendering.dart';
|
||||
|
||||
/// An object in the render tree.
|
||||
///
|
||||
/// The [RenderObject] class hierarchy is the core of the rendering
|
||||
@ -1376,6 +1378,13 @@ class PipelineOwner {
|
||||
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
|
||||
/// Initializes internal fields for subclasses.
|
||||
RenderObject() {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterRenderingLibrary,
|
||||
className: '$RenderObject',
|
||||
object: this,
|
||||
);
|
||||
}
|
||||
_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
|
||||
_wasRepaintBoundary = isRepaintBoundary;
|
||||
}
|
||||
@ -1436,6 +1445,9 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
||||
@mustCallSuper
|
||||
void dispose() {
|
||||
assert(!_debugDisposed);
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
_layerHandle.layer = null;
|
||||
assert(() {
|
||||
// TODO(dnfield): Enable this assert once clients have had a chance to
|
||||
|
@ -816,6 +816,8 @@ enum _StateLifecycle {
|
||||
/// The signature of [State.setState] functions.
|
||||
typedef StateSetter = void Function(VoidCallback fn);
|
||||
|
||||
const String _flutterWidgetsLibrary = 'package:flutter/widgets.dart';
|
||||
|
||||
/// The logic and internal state for a [StatefulWidget].
|
||||
///
|
||||
/// State is information that (1) can be read synchronously when the widget is
|
||||
@ -999,6 +1001,13 @@ abstract class State<T extends StatefulWidget> with Diagnosticable {
|
||||
@mustCallSuper
|
||||
void initState() {
|
||||
assert(_debugLifecycleState == _StateLifecycle.created);
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterWidgetsLibrary,
|
||||
className: '$State',
|
||||
object: this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called whenever the widget configuration changes.
|
||||
@ -1235,6 +1244,9 @@ abstract class State<T extends StatefulWidget> with Diagnosticable {
|
||||
_debugLifecycleState = _StateLifecycle.defunct;
|
||||
return true;
|
||||
}());
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the part of the user interface represented by this widget.
|
||||
@ -3215,7 +3227,15 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
|
||||
/// Typically called by an override of [Widget.createElement].
|
||||
Element(Widget widget)
|
||||
: assert(widget != null),
|
||||
_widget = widget;
|
||||
_widget = widget {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterWidgetsLibrary,
|
||||
className: '$Element',
|
||||
object: this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Element? _parent;
|
||||
DebugReassembleConfig? _debugReassembleConfig;
|
||||
@ -4132,6 +4152,9 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
|
||||
assert(_widget != null); // Use the private property to avoid a CastError during hot reload.
|
||||
assert(depth != null);
|
||||
assert(owner != null);
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
|
||||
}
|
||||
// Use the private property to avoid a CastError during hot reload.
|
||||
final Key? key = _widget?.key;
|
||||
if (key is GlobalKey) {
|
||||
|
64
packages/flutter/test/rendering/memory_allocations_test.dart
Normal file
64
packages/flutter/test/rendering/memory_allocations_test.dart
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
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++;
|
||||
ma.addListener(listener);
|
||||
|
||||
final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents();
|
||||
expect(eventCount, expectedEventCount);
|
||||
|
||||
ma.removeListener(listener);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
});
|
||||
}
|
||||
|
||||
class _TestRenderObject extends RenderObject {
|
||||
@override
|
||||
void debugAssertDoesMeetConstraints() {}
|
||||
|
||||
@override
|
||||
Rect get paintBounds => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void performLayout() {}
|
||||
|
||||
@override
|
||||
void performResize() {}
|
||||
|
||||
@override
|
||||
Rect get semanticBounds => throw UnimplementedError();
|
||||
}
|
||||
|
||||
class _TestLayer extends Layer{
|
||||
@override
|
||||
void addToScene(ui.SceneBuilder builder) {}
|
||||
}
|
||||
|
||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||
Future<int> _activateFlutterObjectsAndReturnCountOfEvents() async {
|
||||
int count = 0;
|
||||
|
||||
final RenderObject renderObject = _TestRenderObject(); count++;
|
||||
final Layer layer = _TestLayer(); count++;
|
||||
|
||||
renderObject.dispose(); count++;
|
||||
layer.dispose(); count++;
|
||||
|
||||
return count;
|
||||
}
|
114
packages/flutter/test/widgets/memory_allocations_test.dart
Normal file
114
packages/flutter/test/widgets/memory_allocations_test.dart
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
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++;
|
||||
ma.addListener(listener);
|
||||
|
||||
final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents();
|
||||
expect(eventCount, expectedEventCount);
|
||||
|
||||
ma.removeListener(listener);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('State dispatches events in debug mode', (WidgetTester tester) async {
|
||||
bool stateCreated = false;
|
||||
bool stateDisposed = false;
|
||||
|
||||
void listener(ObjectEvent event) {
|
||||
if (event is ObjectCreated && event.object is State) {
|
||||
stateCreated = true;
|
||||
}
|
||||
if (event is ObjectDisposed && event.object is State) {
|
||||
stateDisposed = true;
|
||||
}
|
||||
}
|
||||
ma.addListener(listener);
|
||||
|
||||
await tester.pumpWidget(const _TestStatefulWidget());
|
||||
expect(stateCreated, isTrue);
|
||||
expect(stateDisposed, isFalse);
|
||||
await tester.pumpWidget(const SizedBox.shrink());
|
||||
|
||||
expect(stateCreated, isTrue);
|
||||
expect(stateDisposed, isTrue);
|
||||
ma.removeListener(listener);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
});
|
||||
}
|
||||
|
||||
class _TestLeafRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) {
|
||||
return _TestRenderObject();
|
||||
}
|
||||
}
|
||||
|
||||
class _TestElement extends RootRenderObjectElement{
|
||||
_TestElement(): super(_TestLeafRenderObjectWidget());
|
||||
|
||||
void makeInactive() {
|
||||
assignOwner(BuildOwner(focusManager: FocusManager()));
|
||||
mount(null, null);
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
class _TestRenderObject extends RenderObject {
|
||||
@override
|
||||
void debugAssertDoesMeetConstraints() {}
|
||||
|
||||
@override
|
||||
Rect get paintBounds => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void performLayout() {}
|
||||
|
||||
@override
|
||||
void performResize() {}
|
||||
|
||||
@override
|
||||
Rect get semanticBounds => throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
class _TestStatefulWidget extends StatefulWidget {
|
||||
const _TestStatefulWidget();
|
||||
|
||||
@override
|
||||
State<_TestStatefulWidget> createState() => _TestStatefulWidgetState();
|
||||
}
|
||||
|
||||
class _TestStatefulWidgetState extends State<_TestStatefulWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||
Future<int> _activateFlutterObjectsAndReturnCountOfEvents() async {
|
||||
int count = 0;
|
||||
|
||||
final _TestElement element = _TestElement(); count++;
|
||||
final RenderObject renderObject = _TestRenderObject(); count++;
|
||||
|
||||
element.makeInactive(); element.unmount(); count += 3;
|
||||
renderObject.dispose(); count++;
|
||||
|
||||
return count;
|
||||
}
|
@ -19,16 +19,17 @@ void main() {
|
||||
expect(kFlutterMemoryAllocationsEnabled, isFalse);
|
||||
});
|
||||
|
||||
test(
|
||||
testWidgets(
|
||||
'$MemoryAllocations is noop when kFlutterMemoryAllocationsEnabled is false.',
|
||||
() async {
|
||||
(WidgetTester tester) async {
|
||||
ObjectEvent? recievedEvent;
|
||||
ObjectEvent listener(ObjectEvent event) => recievedEvent = event;
|
||||
|
||||
ma.addListener(listener);
|
||||
_checkSdkHandlersNotSet();
|
||||
expect(ma.hasListeners, isFalse);
|
||||
|
||||
await _activateFlutterObjects();
|
||||
await _activateFlutterObjects(tester);
|
||||
_checkSdkHandlersNotSet();
|
||||
expect(recievedEvent, isNull);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
@ -47,16 +48,21 @@ void _checkSdkHandlersNotSet() {
|
||||
}
|
||||
|
||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||
Future<void> _activateFlutterObjects() async {
|
||||
Future<void> _activateFlutterObjects(WidgetTester tester) async {
|
||||
final ValueNotifier<bool> valueNotifier = ValueNotifier<bool>(true);
|
||||
final ChangeNotifier changeNotifier = ChangeNotifier()..addListener(() {});
|
||||
final Image image = await _createImage();
|
||||
final Picture picture = _createPicture();
|
||||
|
||||
valueNotifier.dispose();
|
||||
changeNotifier.dispose();
|
||||
image.dispose();
|
||||
picture.dispose();
|
||||
|
||||
// TODO(polina-c): Remove the condition after
|
||||
// https://github.com/flutter/flutter/issues/110599 is fixed.
|
||||
if (!kIsWeb) {
|
||||
final Image image = await _createImage();
|
||||
image.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Image> _createImage() async {
|
||||
|
@ -0,0 +1,67 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
final MemoryAllocations ma = MemoryAllocations.instance;
|
||||
|
||||
setUp(() {
|
||||
assert(!ma.hasListeners);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'$MemoryAllocations is noop when kFlutterMemoryAllocationsEnabled is false.',
|
||||
(WidgetTester tester) async {
|
||||
ObjectEvent? recievedEvent;
|
||||
ObjectEvent listener(ObjectEvent event) => recievedEvent = event;
|
||||
|
||||
ma.addListener(listener);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
|
||||
await _activateFlutterObjects(tester);
|
||||
expect(recievedEvent, isNull);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
|
||||
ma.removeListener(listener);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _TestRenderObject extends RenderObject {
|
||||
@override
|
||||
void debugAssertDoesMeetConstraints() {}
|
||||
|
||||
@override
|
||||
Rect get paintBounds => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void performLayout() {}
|
||||
|
||||
@override
|
||||
void performResize() {}
|
||||
|
||||
@override
|
||||
Rect get semanticBounds => throw UnimplementedError();
|
||||
}
|
||||
|
||||
class _TestLayer extends Layer{
|
||||
@override
|
||||
void addToScene(SceneBuilder builder) {}
|
||||
}
|
||||
|
||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||
Future<void> _activateFlutterObjects(WidgetTester tester) async {
|
||||
final RenderObject renderObject = _TestRenderObject();
|
||||
final Layer layer = _TestLayer();
|
||||
|
||||
renderObject.dispose();
|
||||
// It is ok to use protected members for testing.
|
||||
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
|
||||
layer.dispose();
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
final MemoryAllocations ma = MemoryAllocations.instance;
|
||||
|
||||
setUp(() {
|
||||
assert(!ma.hasListeners);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'$MemoryAllocations is noop when kFlutterMemoryAllocationsEnabled is false.',
|
||||
(WidgetTester tester) async {
|
||||
ObjectEvent? recievedEvent;
|
||||
ObjectEvent listener(ObjectEvent event) => recievedEvent = event;
|
||||
|
||||
ma.addListener(listener);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
|
||||
await _activateFlutterObjects(tester);
|
||||
expect(recievedEvent, isNull);
|
||||
expect(ma.hasListeners, isFalse);
|
||||
|
||||
ma.removeListener(listener);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _TestLeafRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) {
|
||||
return _TestRenderObject();
|
||||
}
|
||||
}
|
||||
|
||||
class _TestRenderObject extends RenderObject {
|
||||
@override
|
||||
void debugAssertDoesMeetConstraints() {}
|
||||
|
||||
@override
|
||||
Rect get paintBounds => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void performLayout() {}
|
||||
|
||||
@override
|
||||
void performResize() {}
|
||||
|
||||
@override
|
||||
Rect get semanticBounds => throw UnimplementedError();
|
||||
}
|
||||
|
||||
class _TestElement extends RootRenderObjectElement{
|
||||
_TestElement(): super(_TestLeafRenderObjectWidget());
|
||||
|
||||
void makeInactive() {
|
||||
assignOwner(BuildOwner(focusManager: FocusManager()));
|
||||
mount(null, null);
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
class _MyStatefulWidget extends StatefulWidget {
|
||||
const _MyStatefulWidget();
|
||||
|
||||
@override
|
||||
State<_MyStatefulWidget> createState() => _MyStatefulWidgetState();
|
||||
}
|
||||
|
||||
class _MyStatefulWidgetState extends State<_MyStatefulWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and dispose Flutter objects to fire memory allocation events.
|
||||
Future<void> _activateFlutterObjects(WidgetTester tester) async {
|
||||
final _TestElement element = _TestElement();
|
||||
element.makeInactive(); element.unmount();
|
||||
|
||||
// Create and dispose State:
|
||||
await tester.pumpWidget(const _MyStatefulWidget());
|
||||
await tester.pumpWidget(const SizedBox.shrink());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user