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
5f3bee55
Unverified
Commit
5f3bee55
authored
Feb 09, 2022
by
chunhtai
Committed by
GitHub
Feb 09, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow remove listener on disposed change notifier (#97988)
parent
74c4e635
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
28 additions
and
9 deletions
+28
-9
change_notifier.dart
packages/flutter/lib/src/foundation/change_notifier.dart
+15
-5
change_notifier_test.dart
packages/flutter/test/foundation/change_notifier_test.dart
+13
-4
No files found.
packages/flutter/lib/src/foundation/change_notifier.dart
View file @
5f3bee55
...
...
@@ -103,7 +103,12 @@ abstract class ValueListenable<T> extends Listenable {
/// * [ValueNotifier], which is a [ChangeNotifier] that wraps a single value.
class
ChangeNotifier
implements
Listenable
{
int
_count
=
0
;
List
<
VoidCallback
?>
_listeners
=
List
<
VoidCallback
?>.
filled
(
0
,
null
);
// The _listeners is intentionally set to a fixed-length _GrowableList instead
// of const [] for performance reasons.
// See https://github.com/flutter/flutter/pull/71947/files#r545722476 for
// more details.
static
final
List
<
VoidCallback
?>
_emptyListeners
=
List
<
VoidCallback
?>.
filled
(
0
,
null
);
List
<
VoidCallback
?>
_listeners
=
_emptyListeners
;
int
_notificationCallStackDepth
=
0
;
int
_reentrantlyRemovedListeners
=
0
;
bool
_debugDisposed
=
false
;
...
...
@@ -220,7 +225,7 @@ class ChangeNotifier implements Listenable {
///
/// If the given listener is not registered, the call is ignored.
///
/// This method
must not be called after
[dispose] has been called.
/// This method
returns immediately if
[dispose] has been called.
///
/// {@macro flutter.foundation.ChangeNotifier.addListener}
///
...
...
@@ -230,7 +235,11 @@ class ChangeNotifier implements Listenable {
/// changes.
@override
void
removeListener
(
VoidCallback
listener
)
{
assert
(
_debugAssertNotDisposed
());
// This method is allowed to be called on disposed instances for usability
// reasons. Due to how our frame scheduling logic between render objects and
// overlays, it is common that the owner of this instance would be disposed a
// frame earlier than the listeners. Allowing calls to this method after it
// is disposed makes it easier for listeners to properly clean up.
for
(
int
i
=
0
;
i
<
_count
;
i
++)
{
final
VoidCallback
?
listenerAtIndex
=
_listeners
[
i
];
if
(
listenerAtIndex
==
listener
)
{
...
...
@@ -253,8 +262,7 @@ class ChangeNotifier implements Listenable {
/// Discards any resources used by the object. After this is called, the
/// object is not in a usable state and should be discarded (calls to
/// [addListener] and [removeListener] will throw after the object is
/// disposed).
/// [addListener] will throw after the object is disposed).
///
/// This method should only be called by the object's owner.
@mustCallSuper
...
...
@@ -264,6 +272,8 @@ class ChangeNotifier implements Listenable {
_debugDisposed
=
true
;
return
true
;
}());
_listeners
=
_emptyListeners
;
_count
=
0
;
}
/// Call all the registered listeners.
...
...
packages/flutter/test/foundation/change_notifier_test.dart
View file @
5f3bee55
...
...
@@ -323,15 +323,12 @@ void main() {
expect
(
log
,
isEmpty
);
});
test
(
'Cannot use a disposed ChangeNotifier'
,
()
{
test
(
'Cannot use a disposed ChangeNotifier
except for remove listener
'
,
()
{
final
TestNotifier
source
=
TestNotifier
();
source
.
dispose
();
expect
(()
{
source
.
addListener
(()
{});
},
throwsFlutterError
);
expect
(()
{
source
.
removeListener
(()
{});
},
throwsFlutterError
);
expect
(()
{
source
.
dispose
();
},
throwsFlutterError
);
...
...
@@ -340,6 +337,18 @@ void main() {
},
throwsFlutterError
);
});
test
(
'Can remove listener on a disposed ChangeNotifier'
,
()
{
final
TestNotifier
source
=
TestNotifier
();
FlutterError
?
error
;
try
{
source
.
dispose
();
source
.
removeListener
(()
{});
}
on
FlutterError
catch
(
e
)
{
error
=
e
;
}
expect
(
error
,
isNull
);
});
test
(
'Value notifier'
,
()
{
final
ValueNotifier
<
double
>
notifier
=
ValueNotifier
<
double
>(
2.0
);
...
...
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