You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
final newEmail = await container.getString('email');
45
-
print('The email has changed to: $newEmail');
51
+
final newEmail = await container.getString('email');
52
+
print('The email has changed to: $newEmail');
46
53
}
47
54
48
55
// unregister the listener
@@ -54,49 +61,75 @@ Item Holder also supports listeners:
54
61
Item holders itself only holds a single value, so you don't need to specify a key when adding a listener.
55
62
56
63
```dart
64
+
57
65
final itemHolder = storage.itemHolder<String>('status');
58
66
59
67
// Register a listener for changes in the item holder
60
-
itemHolder.addListener(onStatusChanged);
68
+
itemHolder.addListener
69
+
(
70
+
onStatusChanged);
61
71
62
72
void onStatusChanged() async {
63
-
final newStatus = await itemHolder.get();
64
-
print('The status has changed to: $newStatus');
73
+
final newStatus = await itemHolder.get();
74
+
print('The status has changed to: $newStatus');
65
75
}
66
76
67
77
// unregister the listener
68
-
itemHolder.removeListener(onStatusChanged);
78
+
itemHolder
79
+
.
80
+
removeListener
81
+
(
82
+
onStatusChanged
83
+
);
69
84
```
70
85
71
86
## Listening to All Changes
87
+
72
88
You can listen to all changes in the storage, regardless of which key was modified.
73
89
74
90
```dart
75
91
// Register a listener for all changes
76
-
storage.addListener(onStorageChanged);
92
+
storage.addListener
93
+
(
94
+
onStorageChanged);
77
95
78
96
void onStorageChanged() {
79
-
print('The storage has changed.');
97
+
print('The storage has changed.');
80
98
}
81
99
82
100
// unregister the listener
83
-
storage.removeListener(onStorageChanged);
101
+
storage
102
+
.
103
+
removeListener
104
+
(
105
+
onStorageChanged
106
+
);
84
107
```
85
108
86
109
You can also listen to all changes in a named container:
87
110
88
111
```dart
89
-
final container = await storage.container('settings');
112
+
113
+
final container = await
114
+
storage.container
115
+
('settings
116
+
'
117
+
);
90
118
91
119
// Register a listener for all changes in the container
92
120
container.addListener(onSettingsChanged);
93
121
94
122
void onSettingsChanged() {
95
-
print('The settings container has changed.');
123
+
print('The settings container has changed.');
96
124
}
97
125
98
126
// unregister the listener
99
-
container.removeListener(onSettingsChanged);
127
+
container
128
+
.
129
+
removeListener
130
+
(
131
+
onSettingsChanged
132
+
);
100
133
```
101
134
102
135
# Streaming Item Holder Changes
@@ -106,23 +139,18 @@ flexible way, such as using `StreamBuilder` in Flutter.
106
139
107
140
`ItemHolder<E>` extends `ManagedStream<E?>` and implements `Stream<E?>`, so you can listen to it directly.
108
141
109
-
## Implementation Details
110
-
111
-
ItemHolder uses a `BehaviorSubject` (from rxdart) internally, which provides several benefits:
112
-
-**Automatic value caching**: The latest value is cached and automatically emitted to new listeners
113
-
-**Multiple concurrent listeners**: Efficiently supports many listeners without duplicating work
114
-
-**Lazy activation**: Only starts fetching values when someone is actually listening
115
-
116
142
```dart
143
+
117
144
final itemHolder = storage.itemHolder<String>('status');
118
145
119
146
// Listen to changes using Stream API
120
147
final subscription = itemHolder.listen((newStatus) {
121
-
print('The status has changed to: $newStatus');
148
+
print('The status has changed to: $newStatus');
122
149
});
123
150
124
151
// Don't forget to cancel the subscription when it's no longer needed
125
-
subscription.cancel();
152
+
subscription.cancel
153
+
();
126
154
```
127
155
128
156
## Using with StreamBuilder in Flutter
@@ -160,15 +188,16 @@ final valueNotifier = itemHolder.asValueNotifier();
160
188
// Use with ValueListenableBuilder in Flutter
161
189
ValueListenableBuilder<String?>(
162
190
valueListenable: valueNotifier,
163
-
builder: (context, status, child) {
191
+
builder: (context, status, child) {
164
192
return Text('Status: ${status ?? 'Unknown'}');
165
193
},
166
194
);
167
195
```
168
-
> Whenever you call `asValueNotifier`, it creates a new `ValueNotifier` instance. If you want to avoid creating
196
+
197
+
> Whenever you call `asValueNotifier`, it creates a new `ValueNotifier` instance. If you want to avoid creating
169
198
> multiple instances, consider storing the `ValueNotifier` in a variable and reusing it. Remember to dispose the
170
-
> `ValueNotifier` once you no longer need it.
171
-
>
199
+
> `ValueNotifier` once you no longer need it.
200
+
>
172
201
> Make sure to add `hyper_storage_flutter` package to your dependencies to use `asValueNotifier` method.
173
202
174
203
## Streaming key changes
@@ -179,7 +208,7 @@ You can also stream changes for a specific key using the `stream` method.
179
208
// Listen to changes for a specific key
180
209
final nameStream = storage.stream<String>('name');
181
210
final subscription = nameStream.listen((newName) {
182
-
print('The value of "name" has changed to: $newName');
211
+
print('The value of "name" has changed to: $newName');
183
212
});
184
213
// Don't forget to cancel the subscription when it's no longer needed
185
214
subscription.cancel();
@@ -188,54 +217,51 @@ subscription.cancel();
188
217
You can also stream key changes in a named container:
189
218
190
219
```dart
220
+
191
221
final container = await storage.container('user');
192
222
193
223
// Listen to changes for a specific key in the container
194
224
final emailStream = container.stream<String>('email');
195
225
196
226
final subscription = emailStream.listen((newEmail) {
197
-
print('The email has changed to: $newEmail');
227
+
print('The email has changed to: $newEmail');
198
228
});
199
229
200
230
// Don't forget to cancel the subscription when it's no longer needed
201
231
subscription.cancel();
202
232
```
203
233
204
-
## ⚠️ Important: Using Streams with Flutter's StreamBuilder
205
-
206
-
When using streams with Flutter's `StreamBuilder`, it's important to understand the best patterns and practices.
207
-
208
-
### ✅ **The `stream()` Method is Now Safe**
234
+
## Using Streams with Flutter's StreamBuilder
209
235
210
-
As of the latest version, the `stream()` method returns a **cached `ItemHolder` instance**, making it safe to call repeatedly:
236
+
When using streams with Flutter's `StreamBuilder`.
211
237
212
238
```dart
213
-
// These both return the exact same ItemHolder object:
214
-
final stream1 = storage.stream<String>('name');
215
-
final stream2 = storage.stream<String>('name');
216
-
print(identical(stream1, stream2)); // true
239
+
StreamBuilder<String?>(
240
+
stream: storage.stream<String>('name'), // Use directly from storage.
241
+
builder: (context, snapshot) {
242
+
if (snapshot.connectionState == ConnectionState.waiting) {
243
+
return CircularProgressIndicator();
244
+
}
245
+
final name = snapshot.data ?? 'Unknown';
246
+
return Text('Name: $name');
247
+
},
248
+
);
217
249
```
218
250
219
-
This means calling `storage.stream('key')` directly in a build method is now technically safe, as it returns the same cached instance each time. However, for code clarity and best practices, we still recommend the patterns below.
220
-
221
-
### ✅ **Recommended Pattern: Use ItemHolder Directly**
251
+
This means calling `storage.stream('key')` directly in a build method is safe and will not create multiple streams.
222
252
223
-
The clearest and most explicit approach is to use `ItemHolder` directly:
253
+
**Recommended Pattern: Use ItemHolder Directly**: If you have an `ItemHolder` for the key, you can use it directly in
254
+
the `StreamBuilder`. This is the most efficient and clear approach.
0 commit comments