loadStructuredData<T> method
override
Retrieve a string from the asset bundle, parse it with the given function, and return the function's result.
The result of parsing the string is cached (the string itself is not,
unless you also fetch it with loadString). For any given key
, the
parser
is only run the first time.
Once the value has been successfully parsed, the future returned by this function for subsequent calls will be a SynchronousFuture, which resolves its callback synchronously.
Failures are not cached, and are returned as Futures with errors.
Implementation
@override
Future<T> loadStructuredData<T>(String key, Future<T> Function(String value) parser) {
if (_structuredDataCache.containsKey(key)) {
return _structuredDataCache[key]! as Future<T>;
}
// loadString can return a SynchronousFuture in certain cases, like in the
// flutter_test framework. So, we need to support both async and sync flows.
Completer<T>? completer; // For async flow.
Future<T>? synchronousResult; // For sync flow.
loadString(key, cache: false).then<T>(parser).then<void>((T value) {
synchronousResult = SynchronousFuture<T>(value);
_structuredDataCache[key] = synchronousResult!;
if (completer != null) {
// We already returned from the loadStructuredData function, which means
// we are in the asynchronous mode. Pass the value to the completer. The
// completer's future is what we returned.
completer.complete(value);
}
}, onError: (Object error, StackTrace stack) {
assert(completer != null, 'unexpected synchronous failure');
// Either loading or parsing failed. We must report the error back to the
// caller and anyone waiting on this call. We clear the cache for this
// key, however, because we want future attempts to try again.
_structuredDataCache.remove(key);
completer!.completeError(error, stack);
});
if (synchronousResult != null) {
// The above code ran synchronously. We can synchronously return the result.
return synchronousResult!;
}
// The code above hasn't yet run its "then" handler yet. Let's prepare a
// completer for it to use when it does run.
completer = Completer<T>();
_structuredDataCache[key] = completer.future;
return completer.future;
}