getData method
Future<T?>
getData({
- required Future<
T> ? loadCacheFuture, - required Future<
T> ? loadRequestFuture, - BoxerLoadErrorCallback? onLoadError,
Unless loadRequestFuture is completed before loadCacheFuture,
both loadRequestFuture and loadCacheFuture will call howToUpdateView to update the view
loadCacheFuture itself is a cache so there is no need to update the cache
loadRequestFuture will call howToUpdateCache to update the cache after completion
loadCacheFuture and loadRequestFuture can explicitly pass null value
so as to ensure that the caller knows that he has explicitly send a null value
for there is indeed such scenarios:
loadRequestFutureis null, just want to reload the cache data, and update the viewloadCacheFutureis null, just need the requested data to update view and cache, but no need to read the cache
Implementation
Future<T?> getData({
required Future<T>? loadCacheFuture,
required Future<T>? loadRequestFuture,
BoxerLoadErrorCallback? onLoadError,
}) {
Future<T>? f1;
Future<T>? f2;
List<dynamic> results = [Null, Null];
bool isRequestSuccess = false;
() {
f1 = loadRequestFuture;
loadRequestFuture?.then((value) {
results.first = value;
isRequestSuccess = true;
/// Update UI And Cache
update(value, isValueFromCache: false, isOnlyUpdateView: false);
}).onError((e, s) {
(onLoadError ?? this.onLoadError)?.call(e, s, BoxerLoadType.REQUEST);
});
if (isEnableCache == false) return;
f2 = loadCacheFuture;
loadCacheFuture?.then((value) {
/// No need the cache data in this moment, cause request data already response successfully
if (isRequestSuccess) {
BoxerLogger.d(null, "Request data already response, no need to use cache data");
return;
}
results.last = value;
/// Update UI Only
update(value, isValueFromCache: true, isOnlyUpdateView: true);
}).onError((e, s) {
if (isRequestSuccess) {
BoxerLogger.d(null, "Request data already response successfully, no need to call error callback");
return;
}
(onLoadError ?? this.onLoadError)?.call(e, s, BoxerLoadType.CACHE);
});
}();
/// For fallback to the caller, using a completer to return the fallback future.
Completer<T?> wholeCompleter = Completer();
List<Future<T>> futures = [];
if (f1 != null) futures.add(f1!);
if (f2 != null) futures.add(f2!);
if (futures.length > 1) {
futures.first.then((value) {
// if the first future request is ok, then we can complete the whole completer
wholeCompleter.complete(value);
}).onError((e, s) {
// if the first future has error, then we have to wait for the second future
});
}
T? getValue() => results.first != Null ? results.first as T? : (results.last != Null ? results.last as T? : null);
Future.wait(futures).then((value) {
if (wholeCompleter.isCompleted) return;
wholeCompleter.complete(getValue());
}).onError((e, s) {
if (wholeCompleter.isCompleted) return;
wholeCompleter.complete(getValue());
});
return wholeCompleter.future;
}