ch271828n
ch271828n

Reputation: 17567

Reduce the boilerplate of dispose() in Flutter?

In Flutter we need to write down dispose() for many things we have created in a State, e.g.

  final _nameController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

Thus, I wonder whether there is a way to eliminate this need, and call the dispose automatically?

Thanks!

Upvotes: 1

Views: 583

Answers (2)

ch271828n
ch271828n

Reputation: 17567

I find another solution: flutter_hooks

  • Pros: Almost no boilerplate!
  • Cons: Need to extend from a different base class (HookWidget, not StatefulWidget)

One sample:

Before -

class Example extends StatefulWidget {
  final Duration duration;

  const Example({Key key, @required this.duration})
      : assert(duration != null),
        super(key: key);

  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: widget.duration);
  }

  @override
  void didUpdateWidget(Example oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.duration != oldWidget.duration) {
      _controller.duration = widget.duration;
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

After -

class Example extends HookWidget {
  final Duration duration;

  const Example({Key key, @required this.duration})
      : assert(duration != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = useAnimationController(duration: duration);
    return Container();
  }
}

Upvotes: 2

Gregory Conrad
Gregory Conrad

Reputation: 1577

You have a couple options here:

  1. If overriding the dispose method is OK in every State where you need to dispose some objects, simply create a list of all the objects you need to dispose and call dispose on them all at once. Something like this should work:
  @override
  void dispose() {
    [objectToDispose1, objectToDispose2, objectToDispose3].forEach((o) => o.dispose());
    super.dispose();
  }
  1. If you simply do not want to override the dispose method, then you will need to go back to the basics of OOP. Reflection would be very convenient here but Flutter disallows it for performance reasons. Thus, you can make your own abstract base class that extends State, perhaps called DisposableState. This abstract class would have an abstract getter for the objects to dispose as a List. Then, it would reference that getter in its dispose method, using the above method from option 1:
  List get disposables;

  @override
  void dispose() {
    disposables.forEach((o) => o.dispose());
    super.dispose();
  }

Note: you can extend both of these options with objects that have close() instead of dispose(), with some slight modification that adds more boilerplate :(

Unfortunately, I believe this is the shortest way to go about mass-disposing objects as they have to be "registered" for disposal/closing somewhere, and afaik, the Flutter framework does not provide any way to do this in the basic State class.

Upvotes: 1

Related Questions