13

I'm in the early stages of learning Dart & Flutter. I'm looking at how to implement an eventbus, which works fine, but I've noticed that Widgets (and/or their associated state) hold a strong reference to the (global) eventbus, causing a memory leak. The solution is to cancel the subscription in the widget-state's dispose method, but I'd like to know if there's a better approach (I'm coming from Swift which allows variables to be declared as 'weak').

EDIT

I ended up subclassing the state as follows... any better suggestions?

abstract class CustomState<T extends StatefulWidget> extends State {

  List<StreamSubscription> eventSubscriptions = [];

  void subscribeToEvent(Object eventClass, Function callback) {
    StreamSubscription subscription = eventBus.on(eventClass).listen(callback);
    eventSubscriptions.add(subscription);
  }

  void dispose() {
    super.dispose();
    eventSubscriptions.forEach((subscription) => subscription.cancel());
    eventSubscriptions = null;
  }
}

class MyEvent {
  String text;
  MyEvent(this.text);
}

class _MyHomePageState extends CustomState<MyHomePage> {

  @override
  void initState() {
    super.initState();
    subscribeToEvent(MyEvent, onEventFired);
  }

  void onEventFired(event) {
    print('event fired:  ${event.runtimeType}  ${event.text}');
  }
}
hunter
  • 872
  • 10
  • 26
  • 1
    I was wondering if you can make memory cycles in Flutter if you use the delegation pattern from iOS and you can't mark the delegate as weak? – Mircea Dragota Feb 26 '22 at 18:20

3 Answers3

6

Dart doesn't provide weak reference feature.

An Expando has a weak reference behavior though. Not sure if this is of use in your use case.

I sometimes use a Mixin that provides a list where I can add subscriptions and a dispose methode that cancels all subscriptions and add it to widgets and other classes where I need it.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
4

Since dart 2.17 you can use WeakReference.

Any object wrapped in WeakReference(obj) is not kept from being garbage collected.

You access the object via the target property which becomes null when the object got garbage collected.

final myWeakRef = WeakReference(ExampleObj());
// access obj, may be null
print(myWeakRef.target);
Robbendebiene
  • 4,215
  • 3
  • 28
  • 35
  • I'm seriously puzzled that Dart got support for this only this recently. Like, WTH is the point of having a GUI focused language if it can't implement the observer pattern without memory leaks? Is this because of javascript lacking the same functionality and dart technically targeting it, at least initially? – saolof Feb 23 '23 at 23:25
3

As of 2020, I'd like to add to Günter's answer that I've just published a package that goes as close as possible to a weak-reference by implementing a weak-map and a weak-container, as well as cache functions that take advantage of weak references.

It's much easier to use than an Expando (it uses Expando internally).

Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133