auto_dispose_mixin 1.1.0 copy "auto_dispose_mixin: ^1.1.0" to clipboard
auto_dispose_mixin: ^1.1.0 copied to clipboard

A lightweight Flutter mixin that automatically disposes controllers, subscriptions, and other resources to prevent memory leaks.

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)

  • TextEditingController
  • ScrollController, PageController, TabController
  • AnimationController
  • FocusNode, FocusScopeNode
  • SearchController
  • Any custom class extending ChangeNotifier or ValueNotifier

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, EventChannel subscriptions)
  • .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: AutoDisposeMixin must 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 Stopwatch internally
  • Disabled in release mode by default

⚠️ Best Practices #

βœ… DO #

  • Use late final with registerForDispose
  • 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.


1
likes
160
points
217
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight Flutter mixin that automatically disposes controllers, subscriptions, and other resources to prevent memory leaks.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on auto_dispose_mixin