Rules / Correctness / correct-order-for-super-dispose
correct-order-for-super-dispose
Require super.dispose() to be the last call in dispose.
Flags a super.dispose() invocation that is not the final statement of a
dispose method. The base State.dispose tears down the framework's own
bookkeeping for the object, after which touching the widget's fields is
unsafe, so any cleanup your subclass performs must happen first. A
super.dispose() in the middle of the method leaves the remaining cleanup
running against a half-disposed object. Move the super.dispose() call to
the end.
Invalid
example.dartdart
import 'package:flutter/material.dart';
/// Calling super.dispose before cleanup
class BadDisposeOrder extends ChangeNotifier {
late AnimationController controller;
late StreamSubscription subscription;
@override
void dispose() {
super.dispose();
controller.dispose();
subscription.cancel();
}
}
/// Another bad example
class AnotherBadDispose extends ChangeNotifier {
late TextEditingController textController;
late FocusNode focusNode;
@override
void dispose() {
super.dispose();
textController.dispose();
focusNode.dispose();
}
}
/// Multiple resources with super called first
class MultipleResourceDispose extends ChangeNotifier {
late StreamController streamController;
late Timer timer;
@override
void dispose() {
super.dispose();
streamController.close();
timer.cancel();
}
}
/// Bad: super.dispose in middle
class MiddleDispose extends ChangeNotifier {
late ScrollController scrollController;
@override
void dispose() {
scrollController.dispose();
super.dispose();
print('cleanup done');
}
}
/// Bad: early super call with multiple cleanups
class EarlySuper extends ChangeNotifier {
late PageController pageController;
late TabController tabController;
@override
void dispose() {
super.dispose();
pageController.dispose();
tabController.dispose();
}
}
super.dispose() should be called last in the dispose method.
9 void dispose() {
10 super.dispose();
∙
super.dispose() should be called last in the dispose method.
22 void dispose() {
23 super.dispose();
∙
super.dispose() should be called last in the dispose method.
35 void dispose() {
36 super.dispose();
∙
super.dispose() should be called last in the dispose method.
48 scrollController.dispose();
49 super.dispose();
∙
super.dispose() should be called last in the dispose method.
60 void dispose() {
61 super.dispose();
∙
Valid
example.dartdart
import 'package:flutter/material.dart';
/// Cleanup before calling super.dispose
class GoodDisposeOrder extends ChangeNotifier {
late AnimationController controller;
late StreamSubscription subscription;
@override
void dispose() {
controller.dispose();
subscription.cancel();
super.dispose();
}
}
/// Another good example
class AnotherGoodDispose extends ChangeNotifier {
late TextEditingController textController;
late FocusNode focusNode;
@override
void dispose() {
textController.dispose();
focusNode.dispose();
super.dispose();
}
}
/// Multiple resources with correct order
class MultipleResourceDispose extends ChangeNotifier {
late StreamController streamController;
late Timer timer;
@override
void dispose() {
streamController.close();
timer.cancel();
super.dispose();
}
}
/// Single resource cleanup
class SingleResourceDispose extends ChangeNotifier {
late AnimationController animation;
@override
void dispose() {
animation.dispose();
super.dispose();
}
}
/// Good: cleanup with super at end
class ScrollDispose extends ChangeNotifier {
late ScrollController scrollController;
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
}
/// Good: multiple cleanup steps then super
class ComplexDispose extends ChangeNotifier {
late PageController pageController;
late TabController tabController;
late StreamSubscription streamSub;
@override
void dispose() {
pageController.dispose();
tabController.dispose();
streamSub.cancel();
super.dispose();
}
}
How to configure
Set the severity of correct-order-for-super-dispose in your falcon.json:
falcon.jsonjson
{
"linter": {
"rules": {
"correctness": {
"correct-order-for-super-dispose": "error"
}
}
}
}