@@ -12,6 +12,9 @@ import 'package:flutter/foundation.dart' show objectRuntimeType;
1212import '../dart/model.dart' ;
1313
1414/// Signature for the callback passed to [DynamicContent.subscribe] .
15+ ///
16+ /// Do not modify the provided value (e.g. if it is a map or list). Doing so
17+ /// would leave the [DynamicContent] in an inconsistent state.
1518typedef SubscriptionCallback = void Function (Object value);
1619
1720/// Returns a copy of a data structure if it consists of only [DynamicMap] s,
@@ -116,9 +119,12 @@ Object? deepClone(Object? template) {
116119/// [missing] as the new value. It is not an error to subscribe to missing data.
117120/// It _is_ an error to add [missing] values to the data model, however.
118121///
122+ /// To subscribe to the root of the [DynamicContent] , use an empty list as the
123+ /// key when subscribing.
124+ ///
119125/// The [LocalWidgetBuilder] s passed to a [LocalWidgetLibrary] use a
120126/// [DataSource] as their interface into the [DynamicContent] . To ensure the
121- /// integrity of the update mechanism, that interface only allows access to
127+ /// integrity of the update mechanism, _that_ interface only allows access to
122128/// leaves, not intermediate nodes (maps and lists).
123129///
124130/// It is an error to subscribe to the same key multiple times with the same
@@ -143,6 +149,13 @@ class DynamicContent {
143149 /// key.
144150 ///
145151 /// Existing keys that are not present in the given map are left unmodified.
152+ ///
153+ /// If the root node has subscribers (see [subscribe] ), they are called once
154+ /// per key in `initialData` , not just a single time.
155+ ///
156+ /// Collections (maps and lists) in `initialData` must not be mutated after
157+ /// calling this method; doing so would leave the [DynamicContent] in an
158+ /// inconsistent state.
146159 void updateAll (DynamicMap initialData) {
147160 for (final String key in initialData.keys) {
148161 final Object value = initialData[key] ?? missing;
@@ -156,6 +169,10 @@ class DynamicContent {
156169 ///
157170 /// The `value` must consist exclusively of [DynamicMap] , [DynamicList] , [int] ,
158171 /// [double] , [bool] , and [String] objects.
172+ ///
173+ /// Collections (maps and lists) in `value` must not be mutated after calling
174+ /// this method; doing so would leave the [DynamicContent] in an inconsistent
175+ /// state.
159176 void update (String rootKey, Object value) {
160177 _root.updateKey (rootKey, deepClone (value)! );
161178 _scheduleCleanup ();
@@ -167,7 +184,14 @@ class DynamicContent {
167184 /// The value is always non-null; if the value is missing, the [missing]
168185 /// object is used instead.
169186 ///
187+ /// The empty key refers to the root of the [DynamicContent] object (i.e.
188+ /// the map manipulated by [updateAll] and [update] ).
189+ ///
170190 /// Use [unsubscribe] when the subscription is no longer needed.
191+ ///
192+ /// Do not modify the value returned by this method or passed to the given
193+ /// `callback` (e.g. if it is a map or list). Changes made in this manner will
194+ /// leave the [DynamicContent] in an inconsistent state.
171195 Object subscribe (List <Object > key, SubscriptionCallback callback) {
172196 return _root.subscribe (key, 0 , callback);
173197 }
@@ -329,12 +353,6 @@ class _DynamicNode {
329353 _sendUpdates (value);
330354 }
331355
332- void _sendUpdates (Object value) {
333- for (final SubscriptionCallback callback in _callbacks) {
334- callback (value);
335- }
336- }
337-
338356 void updateKey (String rootKey, Object value) {
339357 assert (_value is DynamicMap );
340358 assert (_hasValidType (value));
@@ -345,6 +363,13 @@ class _DynamicNode {
345363 if (_children.containsKey (rootKey)) {
346364 _children[rootKey]! .update (value);
347365 }
366+ _sendUpdates (_value);
367+ }
368+
369+ void _sendUpdates (Object value) {
370+ for (final SubscriptionCallback callback in _callbacks) {
371+ callback (value);
372+ }
348373 }
349374
350375 @override
0 commit comments