Auto Dispose Mixin
Zero-Boilerplate Lifecycle Management for Flutter Widgets
auto_dispose_mixin automatically disposes controllers, subscriptions, notifiers, and custom resources when a StatefulWidget is removed from the widget tree β without overriding dispose().
Designed for performance, safety, and developer ergonomics.
π Why This Package Exists
Memory leaks are one of the most common performance issues in Flutter apps.
Typical problems:
- Forgetting to dispose
TextEditingController - Leaking
StreamSubscription - Missing
AnimationController.dispose() - Bloated
dispose()methods - Inconsistent cleanup across teams
β Traditional Approach
@override
void dispose() {
controller.dispose();
scrollController.dispose();
animationController.dispose();
subscription.cancel();
super.dispose();
}
β With AutoDisposeMixin
class _MyWidgetState extends State<MyWidget>
with AutoDisposeMixin {
late final controller =
registerForDispose(TextEditingController());
// No dispose() override needed π
}
β¨ Features
- β Automatic disposal of common Flutter resources
- β Works with AnimationController (ticker-safe)
- β Stream subscription cleanup
- β Custom disposable objects
- β
Duck typing (
dispose()detection) - β Manual cleanup callbacks
- β DevTools logging
- β Performance timing
- β Zero runtime overhead in release mode
- β No code generation
- β No reflection
- β No magic
π¦ Installation
Add to pubspec.yaml:
dependencies:
auto_dispose_mixin: ^1.*.*
Then run:
flutter pub get
π§© Basic Usage
Step 1: Add the mixin
class _MyPageState extends State<MyPage>
with AutoDisposeMixin {
Step 2: Register disposables
late final TextEditingController controller =
registerForDispose(TextEditingController());
late final ScrollController scrollController =
registerForDispose(ScrollController());
Thatβs it.
No dispose() override required.
π― Supported Disposable Types
AutoDisposeMixin automatically handles an exhaustive list of Flutter and Dart controllers, natively saving you from writing disposal boilerplate.
ChangeNotifier / ValueNotifier Family
(Most UI Controllers)
TextEditingControllerScrollController,PageController,TabControllerAnimationControllerFocusNode,FocusScopeNodeSearchController- Any custom class extending
ChangeNotifierorValueNotifier
Streams & Sinks
(Async Data)
StreamSubscriptionβ.cancel()StreamController,BroadcastStreamControllerβ.close()IOSink,EventSink,WebSocketβ.close()
UI & Flutter Core
OverlayEntryβ Natively calls.remove()if mounted, then.dispose()Timer/RestartableTimerβ.cancel()Tickerβ.stop(),.dispose()
Custom Disposable Interface
abstract class Disposable {
bool get isDisposed;
void dispose();
void markDisposed();
}
Advanced Duck Typing (The "Senior Dev" Checklist)
If your object isn't in the standard Flutter list above, AutoDisposeMixin will dynamically detect and safely call its cleanup method. This automatically handles thousands of 3rd party plugins (like VideoPlayerController, GetX Worker, etc).
The mixin implicitly supports anything that has:
.dispose()(e.g.TapGestureRecognizer, Plugin controllers).cancel()(e.g.Worker,EventChannelsubscriptions).close()(e.g.ReceivePort,PersistentBottomSheetController).kill()(e.g.Isolate)
class FakeSocketClient {
void close() {
print('Socket closed');
}
}
late final socket =
registerForDispose(FakeSocketClient());
Manual Cleanup
registerDisposeCallback(() {
// custom cleanup
});
π AnimationController & Ticker Support
β Correct Mixin Order (IMPORTANT)
When using tickers:
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin, AutoDisposeMixin {
Rule:
AutoDisposeMixinmust be the last mixin.
Why?
- Flutter requires ticker providers to be initialized first
- AutoDisposeMixin depends on fully constructed controllers
π§ Example: AnimationController
late final AnimationController animationController =
registerForDispose(
AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
),
);
The package will:
- Stop animation if running
- Dispose safely
- Track performance (optional)
π StreamSubscription Example
late final StreamSubscription<int> subscription =
registerForDispose(
Stream.periodic(const Duration(seconds: 1))
.listen(print),
);
Automatically calls .cancel() on dispose.
π§ͺ Custom Disposable Example
class FakeSocketClient {
void dispose() {
print('Socket closed');
}
}
late final socket =
registerForDispose(FakeSocketClient());
Duck typing detects .dispose() automatically.
π§Ή Manual Dispose Callback
For edge cases:
registerDisposeCallback(() {
debugPrint('Manual cleanup');
});
Executed after all registered disposables.
π Debug & DevTools Integration
Enable Debug Reporting
void main() {
AutoDisposeDebug.debugReportEnabled = true;
AutoDisposeDebug.trackPerformance = true;
runApp(MyApp());
}
What You Get
- β Per-object dispose logs
- β Non-disposable warnings
- β Total dispose time
- β DevTools timeline visibility
Example output:
Dispose Summary for _MyPageState
---------------------------------
Disposed: 6
Not Disposable: 1
Total Time: 312Β΅s
π Performance Tracking
When enabled:
- Each disposable tracks execution time
- Total dispose duration is logged
- Uses
Stopwatchinternally - Disabled in release mode by default
β οΈ Best Practices
β DO
- Use
late finalwithregisterForDispose - Keep AutoDisposeMixin last
- Enable debug mode during development
β DONβT
- Manually call
.dispose()on registered objects - Register objects after
dispose()is called - Use with non-State classes
π§ͺ Example App
To generate an example project:
flutter create example
Then import your package:
import 'package:auto_dispose_mixin/auto_dispose_mixin.dart';
A full example is included in /example.
π§© Architecture Philosophy
- No code generation
- No build_runner
- No reflection
- No runtime cost
- Flutter-native lifecycle
- Predictable behavior
This package augments Flutter β it does not fight it.
π£ Roadmap
Planned features:
- Leak detection warnings
- DevTools UI extension
- Dispose order visualization
- Zone-based lifecycle scopes
β€οΈ Contributing
Contributions welcome.
- Add new disposable resolvers
- Improve DevTools logging
- Write tests
- Improve documentation
π License
MIT License
https://github.com/ASHISH1317/auto_dispose_mixin/blob/main/LICENSE
β Final Note
If youβve ever forgotten to dispose something in Flutter this package is for you.
Simple. Safe. Fast.