listen<T> method
Enhanced listen with comprehensive memory protection
Implementation
ZenSubscription listen<T>(
dynamic provider,
void Function(T) listener,
) {
// Memory protection - prevent runaway subscriptions
_checkMemoryPressure();
final Type type = T;
final String? tag = _extractTag(provider);
final key = _getKey(type, tag);
// Validate listener count per key
final existingListeners = _listeners[key];
if (existingListeners != null &&
existingListeners.length >= _maxListenersPerKey) {
ZenLogger.logWarning(
'High listener count (${existingListeners.length}) for $type:$tag. Potential memory leak?');
}
_listeners.putIfAbsent(key, () => <VoidCallback>{});
// Create resilient callback using findOrNull to avoid exceptions
void callback() {
try {
final instance = Zen.findOrNull<T>(tag: tag);
if (instance != null) {
listener(instance);
}
} catch (e, stack) {
_errorCount++;
ZenLogger.logError('Error in listener callback for $T', e, stack);
}
}
_listeners[key]!.add(callback);
// Safe initial notification
final current = Zen.findOrNull<T>(tag: tag);
if (current != null) {
try {
listener(current);
} catch (e, stack) {
_errorCount++;
ZenLogger.logError('Error in initial listener call for $T', e, stack);
}
}
// Return enhanced subscription with cleanup tracking
return ZenSubscription(() {
final listenerSet = _listeners[key];
if (listenerSet != null) {
listenerSet.remove(callback);
// Automatic cleanup of empty listener sets
if (listenerSet.isEmpty) {
_listeners.remove(key);
}
}
});
}