2017-08-03 16:40:21 +00:00
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
typedef void _InitCallback();
|
|
|
|
|
|
|
|
/// A [StreamController] boilerplate that prevents memory leaks.
|
|
|
|
abstract class SafeCtrl<T> {
|
2019-05-02 22:48:31 +00:00
|
|
|
factory SafeCtrl() => _SingleSafeCtrl();
|
2017-08-03 16:40:21 +00:00
|
|
|
|
2019-05-02 22:48:31 +00:00
|
|
|
factory SafeCtrl.broadcast() => _BroadcastSafeCtrl();
|
2017-08-03 16:40:21 +00:00
|
|
|
|
|
|
|
Stream<T> get stream;
|
|
|
|
|
|
|
|
void add(T event);
|
|
|
|
|
|
|
|
void addError(error, [StackTrace stackTrace]);
|
|
|
|
|
|
|
|
Future close();
|
|
|
|
|
|
|
|
void whenInitialized(void callback());
|
|
|
|
}
|
|
|
|
|
|
|
|
class _SingleSafeCtrl<T> implements SafeCtrl<T> {
|
|
|
|
StreamController<T> _stream;
|
|
|
|
bool _hasListener = false, _initialized = false;
|
|
|
|
_InitCallback _initializer;
|
|
|
|
|
|
|
|
_SingleSafeCtrl() {
|
2019-05-02 22:48:31 +00:00
|
|
|
_stream = StreamController<T>(onListen: () {
|
2017-08-03 16:40:21 +00:00
|
|
|
_hasListener = true;
|
|
|
|
|
|
|
|
if (!_initialized && _initializer != null) {
|
|
|
|
_initializer();
|
|
|
|
_initialized = true;
|
|
|
|
}
|
|
|
|
}, onPause: () {
|
|
|
|
_hasListener = false;
|
|
|
|
}, onResume: () {
|
|
|
|
_hasListener = true;
|
|
|
|
}, onCancel: () {
|
|
|
|
_hasListener = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Stream<T> get stream => _stream.stream;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void add(T event) {
|
|
|
|
if (_hasListener) _stream.add(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void addError(error, [StackTrace stackTrace]) {
|
|
|
|
if (_hasListener) _stream.addError(error, stackTrace);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Future close() {
|
|
|
|
return _stream.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void whenInitialized(void callback()) {
|
|
|
|
if (!_initialized) {
|
|
|
|
if (!_hasListener)
|
|
|
|
_initializer = callback;
|
|
|
|
else {
|
|
|
|
_initializer();
|
|
|
|
_initialized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _BroadcastSafeCtrl<T> implements SafeCtrl<T> {
|
|
|
|
StreamController<T> _stream;
|
|
|
|
int _listeners = 0;
|
|
|
|
bool _initialized = false;
|
|
|
|
_InitCallback _initializer;
|
|
|
|
|
|
|
|
_BroadcastSafeCtrl() {
|
2019-05-02 22:48:31 +00:00
|
|
|
_stream = StreamController<T>.broadcast(onListen: () {
|
2017-08-03 16:40:21 +00:00
|
|
|
_listeners++;
|
|
|
|
|
|
|
|
if (!_initialized && _initializer != null) {
|
|
|
|
_initializer();
|
|
|
|
_initialized = true;
|
|
|
|
}
|
|
|
|
}, onCancel: () {
|
|
|
|
_listeners--;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Stream<T> get stream => _stream.stream;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void add(T event) {
|
|
|
|
if (_listeners > 0) _stream.add(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void addError(error, [StackTrace stackTrace]) {
|
|
|
|
if (_listeners > 0) _stream.addError(error, stackTrace);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Future close() {
|
|
|
|
return _stream.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void whenInitialized(void callback()) {
|
|
|
|
if (!_initialized) {
|
|
|
|
if (_listeners <= 0)
|
|
|
|
_initializer = callback;
|
|
|
|
else {
|
|
|
|
_initializer();
|
|
|
|
_initialized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|