Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
a3c3dc86
Unverified
Commit
a3c3dc86
authored
Sep 10, 2022
by
Polina Cherkasova
Committed by
GitHub
Sep 10, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create class MemoryAllocations. (#110230)
parent
745d2d44
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
647 additions
and
1 deletion
+647
-1
foundation.dart
packages/flutter/lib/foundation.dart
+1
-0
change_notifier.dart
packages/flutter/lib/src/foundation/change_notifier.dart
+35
-1
memory_allocations.dart
packages/flutter/lib/src/foundation/memory_allocations.dart
+322
-0
memory_allocations_test.dart
...ages/flutter/test/foundation/memory_allocations_test.dart
+214
-0
memory_allocations_test.dart
...tter/test_release/foundation/memory_allocations_test.dart
+75
-0
No files found.
packages/flutter/lib/foundation.dart
View file @
a3c3dc86
...
@@ -34,6 +34,7 @@ export 'src/foundation/isolates.dart';
...
@@ -34,6 +34,7 @@ export 'src/foundation/isolates.dart';
export
'src/foundation/key.dart'
;
export
'src/foundation/key.dart'
;
export
'src/foundation/licenses.dart'
;
export
'src/foundation/licenses.dart'
;
export
'src/foundation/math.dart'
;
export
'src/foundation/math.dart'
;
export
'src/foundation/memory_allocations.dart'
;
export
'src/foundation/node.dart'
;
export
'src/foundation/node.dart'
;
export
'src/foundation/object.dart'
;
export
'src/foundation/object.dart'
;
export
'src/foundation/observer_list.dart'
;
export
'src/foundation/observer_list.dart'
;
...
...
packages/flutter/lib/src/foundation/change_notifier.dart
View file @
a3c3dc86
...
@@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
...
@@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
import
'assertions.dart'
;
import
'assertions.dart'
;
import
'diagnostics.dart'
;
import
'diagnostics.dart'
;
import
'memory_allocations.dart'
;
export
'dart:ui'
show
VoidCallback
;
export
'dart:ui'
show
VoidCallback
;
...
@@ -95,6 +96,8 @@ abstract class ValueListenable<T> extends Listenable {
...
@@ -95,6 +96,8 @@ abstract class ValueListenable<T> extends Listenable {
T
get
value
;
T
get
value
;
}
}
const
String
_flutterFoundationLibrary
=
'package:flutter/foundation.dart'
;
/// A class that can be extended or mixed in that provides a change notification
/// A class that can be extended or mixed in that provides a change notification
/// API using [VoidCallback] for notifications.
/// API using [VoidCallback] for notifications.
///
///
...
@@ -122,6 +125,13 @@ class ChangeNotifier implements Listenable {
...
@@ -122,6 +125,13 @@ class ChangeNotifier implements Listenable {
int
_reentrantlyRemovedListeners
=
0
;
int
_reentrantlyRemovedListeners
=
0
;
bool
_debugDisposed
=
false
;
bool
_debugDisposed
=
false
;
/// If true, the event [ObjectCreated] for this instance was dispatched to
/// [MemoryAllocations].
///
/// As [ChangedNotifier] is used as mixin, it does not have constructor,
/// so we use [addListener] to dispatch the event.
bool
_creationDispatched
=
false
;
/// Used by subclasses to assert that the [ChangeNotifier] has not yet been
/// Used by subclasses to assert that the [ChangeNotifier] has not yet been
/// disposed.
/// disposed.
///
///
...
@@ -204,6 +214,16 @@ class ChangeNotifier implements Listenable {
...
@@ -204,6 +214,16 @@ class ChangeNotifier implements Listenable {
@override
@override
void
addListener
(
VoidCallback
listener
)
{
void
addListener
(
VoidCallback
listener
)
{
assert
(
ChangeNotifier
.
debugAssertNotDisposed
(
this
));
assert
(
ChangeNotifier
.
debugAssertNotDisposed
(
this
));
if
(
kFlutterMemoryAllocationsEnabled
&&
!
_creationDispatched
)
{
MemoryAllocations
.
instance
.
dispatchObjectEvent
(()
{
return
ObjectCreated
(
library
:
_flutterFoundationLibrary
,
className:
'ChangeNotifier'
,
object:
this
,
);
});
_creationDispatched
=
true
;
}
if
(
_count
==
_listeners
.
length
)
{
if
(
_count
==
_listeners
.
length
)
{
if
(
_count
==
0
)
{
if
(
_count
==
0
)
{
_listeners
=
List
<
VoidCallback
?>.
filled
(
1
,
null
);
_listeners
=
List
<
VoidCallback
?>.
filled
(
1
,
null
);
...
@@ -307,6 +327,9 @@ class ChangeNotifier implements Listenable {
...
@@ -307,6 +327,9 @@ class ChangeNotifier implements Listenable {
_debugDisposed
=
true
;
_debugDisposed
=
true
;
return
true
;
return
true
;
}());
}());
if
(
kFlutterMemoryAllocationsEnabled
&&
_creationDispatched
)
{
MemoryAllocations
.
instance
.
dispatchObjectEvent
(()
=>
ObjectDisposed
(
object:
this
));
}
_listeners
=
_emptyListeners
;
_listeners
=
_emptyListeners
;
_count
=
0
;
_count
=
0
;
}
}
...
@@ -441,7 +464,18 @@ class _MergingListenable extends Listenable {
...
@@ -441,7 +464,18 @@ class _MergingListenable extends Listenable {
/// listeners.
/// listeners.
class
ValueNotifier
<
T
>
extends
ChangeNotifier
implements
ValueListenable
<
T
>
{
class
ValueNotifier
<
T
>
extends
ChangeNotifier
implements
ValueListenable
<
T
>
{
/// Creates a [ChangeNotifier] that wraps this value.
/// Creates a [ChangeNotifier] that wraps this value.
ValueNotifier
(
this
.
_value
);
ValueNotifier
(
this
.
_value
)
{
if
(
kFlutterMemoryAllocationsEnabled
)
{
MemoryAllocations
.
instance
.
dispatchObjectEvent
(()
{
return
ObjectCreated
(
library
:
_flutterFoundationLibrary
,
className:
'ValueNotifier'
,
object:
this
,
);
});
}
_creationDispatched
=
true
;
}
/// The current value stored in this notifier.
/// The current value stored in this notifier.
///
///
...
...
packages/flutter/lib/src/foundation/memory_allocations.dart
0 → 100644
View file @
a3c3dc86
// 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
'assertions.dart'
;
import
'constants.dart'
;
import
'diagnostics.dart'
;
const
bool
_kMemoryAllocations
=
bool
.
fromEnvironment
(
'flutter.memory_allocations'
);
/// If true, Flutter objects dispatch the memory allocation events.
///
/// By default, the constant is true for profile and debug mode and false
/// for release mode, for app size optimization goals.
/// To enable the dispatching for release mode, pass the compilation flag
/// `--dart-define=flutter.memory_allocations=true`.
const
bool
kFlutterMemoryAllocationsEnabled
=
_kMemoryAllocations
||
kProfileMode
||
kDebugMode
;
const
String
_dartUiLibrary
=
'dart:ui'
;
class
_FieldNames
{
static
const
String
eventType
=
'eventType'
;
static
const
String
libraryName
=
'libraryName'
;
static
const
String
className
=
'className'
;
}
/// A lifecycle event of an object.
abstract
class
ObjectEvent
{
/// Creates an instance of [ObjectEvent].
ObjectEvent
({
required
this
.
object
,
});
/// Reference to the object.
///
/// The reference should not be stored in any
/// long living place as it will prevent garbage collection.
final
Object
object
;
/// The representation of the event in a form, acceptible by a
/// pure dart library, that cannot depend on Flutter.
///
/// The method enables code like:
/// ```dart
/// void myDartMethod(Map<Object, Map<String, Object>> event) {}
/// MemoryAllocations.instance
/// .addListener((ObjectEvent event) => myDartMethod(event.toMap()));
/// ```
Map
<
Object
,
Map
<
String
,
Object
>>
toMap
();
}
/// A listener of [ObjectEvent].
typedef
ObjectEventListener
=
void
Function
(
ObjectEvent
);
/// A builder of [ObjectEvent].
typedef
ObjectEventBuilder
=
ObjectEvent
Function
();
/// An event that describes creation of an object.
class
ObjectCreated
extends
ObjectEvent
{
/// Creates an instance of [ObjectCreated].
ObjectCreated
({
required
this
.
library
,
required
this
.
className
,
required
super
.
object
,
});
/// Name of the instrumented library.
final
String
library
;
/// Name of the instrumented class.
final
String
className
;
@override
Map
<
Object
,
Map
<
String
,
Object
>>
toMap
()
{
return
<
Object
,
Map
<
String
,
Object
>>{
object:
<
String
,
Object
>{
_FieldNames
.
libraryName
:
library
,
_FieldNames
.
className
:
className
,
_FieldNames
.
eventType
:
'created'
,
}};
}
}
/// An event that describes disposal of an object.
class
ObjectDisposed
extends
ObjectEvent
{
/// Creates an instance of [ObjectDisposed].
ObjectDisposed
({
required
super
.
object
,
});
@override
Map
<
Object
,
Map
<
String
,
Object
>>
toMap
()
{
return
<
Object
,
Map
<
String
,
Object
>>{
object:
<
String
,
Object
>{
_FieldNames
.
eventType
:
'disposed'
,
}};
}
}
/// An interface for listening to object lifecycle events.
///
/// If [kFlutterMemoryAllocationsEnabled] is true,
/// [MemoryAllocations] listens to creation and disposal events
/// for disposable objects in Flutter Framework.
/// To dispatch events for other objects, invoke
/// [MemoryAllocations.dispatchObjectEvent].
///
/// Use this class with condition `kFlutterMemoryAllocationsEnabled`,
/// to make sure not to increase size of the application by the code
/// of the class, if memory allocations are disabled.
///
/// The class is optimized for massive event flow and small number of
/// added or removed listeners.
class
MemoryAllocations
{
MemoryAllocations
.
_
();
/// The shared instance of [MemoryAllocations].
///
/// Only call this when [kFlutterMemoryAllocationsEnabled] is true.
static
final
MemoryAllocations
instance
=
MemoryAllocations
.
_
();
/// List of listeners.
///
/// The elements are nullable, because the listeners should be removable
/// while iterating through the list.
List
<
ObjectEventListener
?>?
_listeners
;
/// Register a listener that is called every time an object event is
/// dispatched.
///
/// Listeners can be removed with [removeListener].
///
/// Only call this when [kFlutterMemoryAllocationsEnabled] is true.
void
addListener
(
ObjectEventListener
listener
){
if
(!
kFlutterMemoryAllocationsEnabled
)
{
return
;
}
if
(
_listeners
==
null
)
{
_listeners
=
<
ObjectEventListener
?>[];
_subscribeToSdkObjects
();
}
_listeners
!.
add
(
listener
);
}
/// Number of active notification loops.
///
/// When equal to zero, we can delete listeners from the list,
/// otherwise should null them.
int
_activeDispatchLoops
=
0
;
/// If true, listeners were nulled by [removeListener].
bool
_listenersContainNulls
=
false
;
/// Stop calling the given listener every time an object event is
/// dispatched.
///
/// Listeners can be added with [addListener].
///
/// Only call this when [kFlutterMemoryAllocationsEnabled] is true.
void
removeListener
(
ObjectEventListener
listener
){
if
(!
kFlutterMemoryAllocationsEnabled
)
{
return
;
}
final
List
<
ObjectEventListener
?>?
listeners
=
_listeners
;
if
(
listeners
==
null
)
{
return
;
}
if
(
_activeDispatchLoops
>
0
)
{
// If there are active dispatch loops, listeners.remove
// should not be invoked, as it will
// break the dispatch loops correctness.
for
(
int
i
=
0
;
i
<
listeners
.
length
;
i
++)
{
if
(
listeners
[
i
]
==
listener
)
{
listeners
[
i
]
=
null
;
_listenersContainNulls
=
true
;
}
}
}
else
{
listeners
.
removeWhere
((
ObjectEventListener
?
l
)
=>
l
==
listener
);
_checkListenersForEmptiness
();
}
}
void
_tryDefragmentListeners
()
{
if
(
_activeDispatchLoops
>
0
||
!
_listenersContainNulls
)
{
return
;
}
_listeners
?.
removeWhere
((
ObjectEventListener
?
e
)
=>
e
==
null
);
_listenersContainNulls
=
false
;
_checkListenersForEmptiness
();
}
void
_checkListenersForEmptiness
()
{
if
(
_listeners
?.
isEmpty
??
false
)
{
_listeners
=
null
;
_unSubscribeFromSdkObjects
();
}
}
/// Return true if there are listeners.
///
/// If there is no listeners, the app can save on creating the event object.
///
/// Only call this when [kFlutterMemoryAllocationsEnabled] is true.
bool
get
hasListeners
{
if
(!
kFlutterMemoryAllocationsEnabled
)
{
return
false
;
}
if
(
_listenersContainNulls
)
{
return
_listeners
?.
firstWhere
((
ObjectEventListener
?
l
)
=>
l
!=
null
)
!=
null
;
}
return
_listeners
?.
isNotEmpty
??
false
;
}
/// Dispatch a new object event to listeners.
///
/// Exceptions thrown by listeners will be caught and reported using
/// [FlutterError.reportError].
///
/// Listeners added during an event dispatching, will start being invoked
/// for next events, but will be skipped for this event.
///
/// Listeners, removed during an event dispatching, will not be invoked
/// after the removal.
///
/// Only call this when [kFlutterMemoryAllocationsEnabled] is true.
void
dispatchObjectEvent
(
ObjectEventBuilder
objectEventBuilder
)
{
if
(!
kFlutterMemoryAllocationsEnabled
)
{
return
;
}
final
List
<
ObjectEventListener
?>?
listeners
=
_listeners
;
if
(
listeners
==
null
||
listeners
.
isEmpty
)
{
return
;
}
final
ObjectEvent
event
=
objectEventBuilder
();
_activeDispatchLoops
++;
final
int
end
=
listeners
.
length
;
for
(
int
i
=
0
;
i
<
end
;
i
++)
{
try
{
listeners
[
i
]?.
call
(
event
);
}
catch
(
exception
,
stack
)
{
final
String
type
=
event
.
object
.
runtimeType
.
toString
();
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'foundation library'
,
context:
ErrorDescription
(
'MemoryAllocations while '
'dispatching notifications for
$type
'
),
informationCollector:
()
=>
<
DiagnosticsNode
>[
DiagnosticsProperty
<
Object
>(
'The
$type
sending notification was'
,
event
.
object
,
style:
DiagnosticsTreeStyle
.
errorProperty
,
),
],
));
}
}
_activeDispatchLoops
--;
_tryDefragmentListeners
();
}
void
_subscribeToSdkObjects
()
{
assert
(
ui
.
Image
.
onCreate
==
null
);
assert
(
ui
.
Image
.
onDispose
==
null
);
assert
(
ui
.
Picture
.
onCreate
==
null
);
assert
(
ui
.
Picture
.
onDispose
==
null
);
ui
.
Image
.
onCreate
=
_imageOnCreate
;
ui
.
Image
.
onDispose
=
_imageOnDispose
;
ui
.
Picture
.
onCreate
=
_pictureOnCreate
;
ui
.
Picture
.
onDispose
=
_pictureOnDispose
;
}
void
_unSubscribeFromSdkObjects
()
{
assert
(
ui
.
Image
.
onCreate
==
_imageOnCreate
);
assert
(
ui
.
Image
.
onDispose
==
_imageOnDispose
);
assert
(
ui
.
Picture
.
onCreate
==
_pictureOnCreate
);
assert
(
ui
.
Picture
.
onDispose
==
_pictureOnDispose
);
ui
.
Image
.
onCreate
=
null
;
ui
.
Image
.
onDispose
=
null
;
ui
.
Picture
.
onCreate
=
null
;
ui
.
Picture
.
onDispose
=
null
;
}
void
_imageOnCreate
(
ui
.
Image
image
)
{
dispatchObjectEvent
(()
{
return
ObjectCreated
(
library
:
_dartUiLibrary
,
className:
'Image'
,
object:
image
,
);
});
}
void
_pictureOnCreate
(
ui
.
Picture
picture
)
{
dispatchObjectEvent
(()
{
return
ObjectCreated
(
library
:
_dartUiLibrary
,
className:
'Picture'
,
object:
picture
,
);
});
}
void
_imageOnDispose
(
ui
.
Image
image
)
{
dispatchObjectEvent
(()
{
return
ObjectDisposed
(
object:
image
,
);
});
}
void
_pictureOnDispose
(
ui
.
Picture
picture
)
{
dispatchObjectEvent
(()
{
return
ObjectDisposed
(
object:
picture
,
);
});
}
}
packages/flutter/test/foundation/memory_allocations_test.dart
0 → 100644
View file @
a3c3dc86
// 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_test/flutter_test.dart'
;
void
main
(
)
{
final
MemoryAllocations
ma
=
MemoryAllocations
.
instance
;
setUp
(()
{
assert
(!
ma
.
hasListeners
);
_checkSdkHandlersNotSet
();
});
test
(
'addListener and removeListener add and remove listeners.'
,
()
{
final
ObjectEvent
event
=
ObjectDisposed
(
object:
'object'
);
ObjectEvent
?
recievedEvent
;
void
listener
(
ObjectEvent
event
)
=>
recievedEvent
=
event
;
expect
(
ma
.
hasListeners
,
isFalse
);
ma
.
addListener
(
listener
);
_checkSdkHandlersSet
();
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
recievedEvent
,
equals
(
event
));
expect
(
ma
.
hasListeners
,
isTrue
);
recievedEvent
=
null
;
ma
.
removeListener
(
listener
);
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
recievedEvent
,
isNull
);
expect
(
ma
.
hasListeners
,
isFalse
);
_checkSdkHandlersNotSet
();
});
testWidgets
(
'dispatchObjectEvent handles bad listeners'
,
(
WidgetTester
tester
)
async
{
final
ObjectEvent
event
=
ObjectDisposed
(
object:
'object'
);
final
List
<
String
>
log
=
<
String
>[];
void
badListener1
(
ObjectEvent
event
)
{
log
.
add
(
'badListener1'
);
throw
ArgumentError
();
}
void
listener1
(
ObjectEvent
event
)
=>
log
.
add
(
'listener1'
);
void
badListener2
(
ObjectEvent
event
)
{
log
.
add
(
'badListener2'
);
throw
ArgumentError
();
}
void
listener2
(
ObjectEvent
event
)
=>
log
.
add
(
'listener2'
);
ma
.
addListener
(
badListener1
);
_checkSdkHandlersSet
();
ma
.
addListener
(
listener1
);
ma
.
addListener
(
badListener2
);
ma
.
addListener
(
listener2
);
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[
'badListener1'
,
'listener1'
,
'badListener2'
,
'listener2'
]);
expect
(
tester
.
takeException
(),
contains
(
'Multiple exceptions (2)'
));
ma
.
removeListener
(
badListener1
);
_checkSdkHandlersSet
();
ma
.
removeListener
(
listener1
);
ma
.
removeListener
(
badListener2
);
ma
.
removeListener
(
listener2
);
_checkSdkHandlersNotSet
();
log
.
clear
();
expect
(
ma
.
hasListeners
,
isFalse
);
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[]);
});
test
(
'dispatchObjectEvent does not invoke concurrently added listeners'
,
()
{
final
ObjectEvent
event
=
ObjectDisposed
(
object:
'object'
);
final
List
<
String
>
log
=
<
String
>[];
void
listener2
(
ObjectEvent
event
)
=>
log
.
add
(
'listener2'
);
void
listener1
(
ObjectEvent
event
)
{
log
.
add
(
'listener1'
);
ma
.
addListener
(
listener2
);
}
ma
.
addListener
(
listener1
);
_checkSdkHandlersSet
();
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[
'listener1'
]);
log
.
clear
();
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[
'listener1'
,
'listener2'
]);
log
.
clear
();
ma
.
removeListener
(
listener1
);
ma
.
removeListener
(
listener2
);
_checkSdkHandlersNotSet
();
expect
(
ma
.
hasListeners
,
isFalse
);
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[]);
});
test
(
'dispatchObjectEvent does not invoke concurrently removed listeners'
,
()
{
final
ObjectEvent
event
=
ObjectDisposed
(
object:
'object'
);
final
List
<
String
>
log
=
<
String
>[];
void
listener2
(
ObjectEvent
event
)
=>
log
.
add
(
'listener2'
);
void
listener1
(
ObjectEvent
event
)
{
log
.
add
(
'listener1'
);
ma
.
removeListener
(
listener2
);
expect
(
ma
.
hasListeners
,
isFalse
);
}
ma
.
addListener
(
listener1
);
ma
.
addListener
(
listener2
);
ma
.
dispatchObjectEvent
(()
=>
event
);
expect
(
log
,
<
String
>[
'listener1'
]);
log
.
clear
();
ma
.
removeListener
(
listener1
);
_checkSdkHandlersNotSet
();
expect
(
ma
.
hasListeners
,
isFalse
);
});
test
(
'last removeListener unsubscribes from Flutter SDK events'
,
()
{
void
listener1
(
ObjectEvent
event
)
{}
void
listener2
(
ObjectEvent
event
)
{}
ma
.
addListener
(
listener1
);
_checkSdkHandlersSet
();
ma
.
addListener
(
listener2
);
_checkSdkHandlersSet
();
ma
.
removeListener
(
listener1
);
_checkSdkHandlersSet
();
ma
.
removeListener
(
listener2
);
_checkSdkHandlersNotSet
();
});
test
(
'kFlutterMemoryAllocationsEnabled is true in debug mode.'
,
()
{
expect
(
kFlutterMemoryAllocationsEnabled
,
isTrue
);
});
test
(
'publishers in Flutter 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
);
_checkSdkHandlersNotSet
();
expect
(
ma
.
hasListeners
,
isFalse
);
});
}
void
_checkSdkHandlersSet
(
)
{
expect
(
Image
.
onCreate
,
isNotNull
);
expect
(
Picture
.
onCreate
,
isNotNull
);
expect
(
Image
.
onDispose
,
isNotNull
);
expect
(
Picture
.
onDispose
,
isNotNull
);
}
void
_checkSdkHandlersNotSet
(
)
{
expect
(
Image
.
onCreate
,
isNull
);
expect
(
Picture
.
onCreate
,
isNull
);
expect
(
Image
.
onDispose
,
isNull
);
expect
(
Picture
.
onDispose
,
isNull
);
}
/// Create and dispose Flutter objects to fire memory allocation events.
Future
<
int
>
_activateFlutterObjectsAndReturnCountOfEvents
()
async
{
int
count
=
0
;
final
ValueNotifier
<
bool
>
valueNotifier
=
ValueNotifier
<
bool
>(
true
);
count
++;
final
ChangeNotifier
changeNotifier
=
ChangeNotifier
()..
addListener
(()
{});
count
++;
final
Picture
picture
=
_createPicture
();
count
++;
valueNotifier
.
dispose
();
count
++;
changeNotifier
.
dispose
();
count
++;
picture
.
dispose
();
count
++;
// TODO(polina-c): Remove the condition after
// https://github.com/flutter/flutter/issues/110599 is fixed.
if
(!
kIsWeb
)
{
final
Image
image
=
await
_createImage
();
count
++;
count
++;
count
++;
image
.
dispose
();
count
++;
}
return
count
;
}
Future
<
Image
>
_createImage
()
async
{
final
Picture
picture
=
_createPicture
();
final
Image
result
=
await
picture
.
toImage
(
10
,
10
);
picture
.
dispose
();
return
result
;
}
Picture
_createPicture
(
)
{
final
PictureRecorder
recorder
=
PictureRecorder
();
final
Canvas
canvas
=
Canvas
(
recorder
);
const
Rect
rect
=
Rect
.
fromLTWH
(
0.0
,
0.0
,
100.0
,
100.0
);
canvas
.
clipRect
(
rect
);
return
recorder
.
endRecording
();
}
packages/flutter/test_release/foundation/memory_allocations_test.dart
0 → 100644
View file @
a3c3dc86
// 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_test/flutter_test.dart'
;
void
main
(
)
{
final
MemoryAllocations
ma
=
MemoryAllocations
.
instance
;
setUp
(()
{
assert
(!
ma
.
hasListeners
);
_checkSdkHandlersNotSet
();
});
test
(
'kFlutterMemoryAllocationsEnabled is false in release mode.'
,
()
{
expect
(
kFlutterMemoryAllocationsEnabled
,
isFalse
);
});
test
(
'
$MemoryAllocations
is noop when kFlutterMemoryAllocationsEnabled is false.'
,
()
async
{
ObjectEvent
?
recievedEvent
;
ObjectEvent
listener
(
ObjectEvent
event
)
=>
recievedEvent
=
event
;
ma
.
addListener
(
listener
);
_checkSdkHandlersNotSet
();
await
_activateFlutterObjects
();
_checkSdkHandlersNotSet
();
expect
(
recievedEvent
,
isNull
);
expect
(
ma
.
hasListeners
,
isFalse
);
ma
.
removeListener
(
listener
);
_checkSdkHandlersNotSet
();
},
);
}
void
_checkSdkHandlersNotSet
(
)
{
expect
(
Image
.
onCreate
,
isNull
);
expect
(
Picture
.
onCreate
,
isNull
);
expect
(
Image
.
onDispose
,
isNull
);
expect
(
Picture
.
onDispose
,
isNull
);
}
/// Create and dispose Flutter objects to fire memory allocation events.
Future
<
void
>
_activateFlutterObjects
()
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
();
}
Future
<
Image
>
_createImage
()
async
{
final
Picture
picture
=
_createPicture
();
final
Image
result
=
await
picture
.
toImage
(
10
,
10
);
picture
.
dispose
();
return
result
;
}
Picture
_createPicture
(
)
{
final
PictureRecorder
recorder
=
PictureRecorder
();
final
Canvas
canvas
=
Canvas
(
recorder
);
const
Rect
rect
=
Rect
.
fromLTWH
(
0.0
,
0.0
,
100.0
,
100.0
);
canvas
.
clipRect
(
rect
);
return
recorder
.
endRecording
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment