observeRealtimeDBValue<T> method
/////////////// /////////////// Observes a specific field in a Firestore document in real-time.
documentPath
: Path to the Firestore document.fieldPath
: Path to the nested field within the document (e.g., "data/lastUpdatedTime").
Returns a ValueNotifier that emits updates whenever the specified field changes.
Usage Example:
ValueNotifier<String?> notifier = rtdb.observeRealtimeDBValue<String>('users/user123', 'profile/name');
notifier.addListener(() {
print('Name updated to: ${notifier.value}');
});
Implementation
// Real-Time Observation //
//////////////////
/// Observes a specific field in a Firestore document in real-time.
///
/// - [documentPath]: Path to the Firestore document.
/// - [fieldPath]: Path to the nested field within the document (e.g., "data/lastUpdatedTime").
///
/// Returns a [ValueNotifier] that emits updates whenever the specified field changes.
///
/// **Usage Example**:
/// ```dart
/// ValueNotifier<String?> notifier = rtdb.observeRealtimeDBValue<String>('users/user123', 'profile/name');
/// notifier.addListener(() {
/// print('Name updated to: ${notifier.value}');
/// });
/// ```
Future<ValueNotifier<T?>> observeRealtimeDBValue<T>(String path) async {
if (_listenedValues.containsKey(path)) {
return _listenedValues[path] as ValueNotifier<T?>;
}
final notifier = ValueNotifier<T?>(null);
// Fetch initial data
try {
final initialData = await getData(path);
if (initialData is T) {
notifier.value = initialData;
} else {
notifier.value = null;
if (debug) {
debugPrint(
'Type mismatch: Expected type $T, but got ${initialData.runtimeType} for path $path.');
}
}
} catch (error) {
debugPrint('Error fetching initial data for $path: $error');
}
// Set up real-time observation using streams
final streamController = _observeData(path);
streamController.stream.listen((data) {
if (data is T && data != notifier.value) {
notifier.value = data;
} else if (data is! T) {
debugPrint(
'Type mismatch: Expected type $T, but got ${data.runtimeType} for path $path.');
notifier.value = null;
}
}, onError: (error) {
debugPrint('Error observing Realtime Database value at $path: $error');
notifier.value = null;
});
// Clean up when there are no listeners
notifier.addListener(() {
if (!notifier.hasListeners) {
streamController.close();
if (debug) {
debugPrint('Subscription canceled for $path');
}
}
});
_listenedValues[path] = notifier;
return notifier;
}