Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved super.dispose down #803

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# x.x.x

- Fix dispose order wrong (#802)

# 6.0.5

- Fix broken links on pub.dev
Expand Down
4 changes: 2 additions & 2 deletions lib/src/deferred_inherited_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ DeferredInheritedProvider(

@override
void dispose() {
super.dispose();
_removeListener?.call();
super.dispose();
}

bool get isLoaded => _removeListener != null;
Expand Down Expand Up @@ -218,10 +218,10 @@ class _CreateDeferredInheritedProviderElement<T, R>

@override
void dispose() {
super.dispose();
if (_didBuild) {
delegate.dispose?.call(element!, _controller as T);
}
super.dispose();
}

@override
Expand Down
2 changes: 2 additions & 0 deletions lib/src/devtool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class PostEventSpy {
PostEventSpy._();
final logs = <PostEventCall>[];

/// Disposes the spy. All implementations must end with the call `super.dispose()`.
@mustCallSuper
void dispose() {
assert(
_debugPostEventOverride == _postEvent,
Expand Down
6 changes: 4 additions & 2 deletions lib/src/inherited_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,8 @@ abstract class _DelegateState<T, D extends _Delegate<T>> {

bool willUpdateDelegate(D newDelegate) => false;

/// Disposes the delegate. All implementations must end with the call `super.dispose()`.
@mustCallSuper
void dispose() {}

void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
Expand Down Expand Up @@ -791,11 +793,11 @@ class _CreateInheritedProviderState<T>

@override
void dispose() {
super.dispose();
_removeListener?.call();
if (_didInitValue) {
delegate.dispose?.call(element!, _value as T);
}
super.dispose();
}

@override
Expand Down Expand Up @@ -950,8 +952,8 @@ class _ValueInheritedProviderState<T>

@override
void dispose() {
super.dispose();
_removeListener?.call();
super.dispose();
}

@override
Expand Down
57 changes: 57 additions & 0 deletions test/null_safe/change_notifier_provider_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,61 @@ void main() {

expect(myNotifier.notifyListeners, throwsAssertionError);
});

testWidgets('call dispose after removing listeners', (tester) async {
final notifier = _ChangeNotifierDisposeTest();
final widget = ChangeNotifierProvider(
create: (_) => notifier,
builder: (context, __) => Text(
Provider.of<_ChangeNotifierDisposeTest>(context).text,
textDirection: TextDirection.ltr,
),
);

await tester.pumpWidget(widget);
await tester.pumpAndSettle();

// If the listener is removed after the super.dispose, this will throw
rrousselGit marked this conversation as resolved.
Show resolved Hide resolved
await tester.pumpWidget(Container());
await tester.pumpAndSettle();
});
}

class _ChangeNotifierDisposeTest with _ChangeNotifierDispose {
final String text = 'test';
}

mixin _ChangeNotifierDispose implements ChangeNotifier {
var _disposed = false;
var _listeners = 0;

@override
void dispose() {
_disposed = true;
if (_listeners != 0) {
throw Exception('listeners not removed before dispose');
}
}

@override
void removeListener(VoidCallback listener) {
_listeners--;
if (_disposed) {
throw Exception('disposed when removing listener');
}
}

@override
void addListener(VoidCallback listener) {
_listeners++;
if (_disposed) {
throw Exception('disposed when adding listener');
}
}

@override
bool get hasListeners => _listeners > 0;

@override
void notifyListeners() {}
}