improved performance and battery usage on older devices
This commit is contained in:
+44
-40
@@ -1,10 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:localstore/localstore.dart';
|
||||
|
||||
import '../model/account_data.dart';
|
||||
import 'api_response.dart';
|
||||
import 'cache_store.dart';
|
||||
import 'errors/parse_exception.dart';
|
||||
import 'errors/stale_session_exception.dart';
|
||||
|
||||
@@ -14,12 +13,10 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
static const int cacheHour = 60 * 60;
|
||||
static const int cacheDay = 60 * 60 * 24;
|
||||
|
||||
static String collection = 'MarianumMobile';
|
||||
|
||||
int maxCacheTime;
|
||||
void Function(T)? onUpdate;
|
||||
|
||||
/// Called only when [start] finds a cached payload in localstore. Use this
|
||||
/// Called only when [start] finds a cached payload in the [CacheStore]. Use this
|
||||
/// (instead of [onUpdate]) when callers need to distinguish stale-but-fast
|
||||
/// cache hits from authoritative network responses.
|
||||
void Function(T)? onCacheData;
|
||||
@@ -52,47 +49,55 @@ abstract class RequestCache<T extends ApiResponse?> {
|
||||
Future<void> start(String document) async {
|
||||
final epoch = AccountData().sessionEpoch;
|
||||
try {
|
||||
final tableData = await Localstore.instance
|
||||
.collection(collection)
|
||||
.doc(document)
|
||||
.get();
|
||||
if (tableData != null) {
|
||||
final cached = onLocalData(tableData['json'] as String);
|
||||
final entry = await CacheStore.instance.read(document);
|
||||
var lastUpdate = entry?.lastUpdate ?? 0;
|
||||
T? cached;
|
||||
if (entry != null) {
|
||||
try {
|
||||
cached = fromCacheJson(await CacheStore.decode(entry.json));
|
||||
} on Object {
|
||||
// A payload from an older model version: treat it as a miss.
|
||||
await CacheStore.instance.delete(document);
|
||||
lastUpdate = 0;
|
||||
}
|
||||
}
|
||||
if (cached != null) {
|
||||
onUpdate?.call(cached);
|
||||
onCacheData?.call(cached);
|
||||
}
|
||||
|
||||
final lastUpdate = (tableData?['lastupdate'] as num?) ?? 0;
|
||||
if (DateTime.now().millisecondsSinceEpoch - (maxCacheTime * 1000) <
|
||||
lastUpdate) {
|
||||
if (renew == null || !renew!) return;
|
||||
}
|
||||
|
||||
try {
|
||||
final newValue = await onLoad();
|
||||
// The collection is shared, so a late response of a signed-out
|
||||
// account would otherwise be cached for the next one.
|
||||
if (!AccountData().isCurrentSession(epoch)) {
|
||||
onError(const StaleSessionException());
|
||||
return;
|
||||
}
|
||||
onUpdate?.call(newValue);
|
||||
onNetworkData?.call(newValue);
|
||||
unawaited(
|
||||
Localstore.instance.collection(collection).doc(document).set({
|
||||
'json': jsonEncode(newValue),
|
||||
'lastupdate': DateTime.now().millisecondsSinceEpoch,
|
||||
}),
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
onError(e);
|
||||
}
|
||||
await _load(document, epoch, lastUpdate: lastUpdate);
|
||||
} finally {
|
||||
if (!_ready.isCompleted) _ready.complete();
|
||||
}
|
||||
}
|
||||
|
||||
T onLocalData(String json);
|
||||
Future<void> _load(
|
||||
String document,
|
||||
int epoch, {
|
||||
required int lastUpdate,
|
||||
}) async {
|
||||
if (DateTime.now().millisecondsSinceEpoch - (maxCacheTime * 1000) <
|
||||
lastUpdate) {
|
||||
if (renew == null || !renew!) return;
|
||||
}
|
||||
|
||||
try {
|
||||
final newValue = await onLoad();
|
||||
// The cache is shared, so a late response of a signed-out
|
||||
// account would otherwise be cached for the next one.
|
||||
if (!AccountData().isCurrentSession(epoch)) {
|
||||
onError(const StaleSessionException());
|
||||
return;
|
||||
}
|
||||
onUpdate?.call(newValue);
|
||||
onNetworkData?.call(newValue);
|
||||
unawaited(CacheStore.instance.write(document, jsonEncode(newValue)));
|
||||
} on Exception catch (e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
T fromCacheJson(Map<String, dynamic> json);
|
||||
Future<T> onLoad();
|
||||
}
|
||||
|
||||
@@ -126,8 +131,7 @@ class SimpleCache<T extends ApiResponse?> extends RequestCache<T> {
|
||||
Future<T> onLoad() => _loader();
|
||||
|
||||
@override
|
||||
T onLocalData(String json) =>
|
||||
_fromJson(jsonDecode(json) as Map<String, dynamic>);
|
||||
T fromCacheJson(Map<String, dynamic> json) => _fromJson(json);
|
||||
}
|
||||
|
||||
/// Captures the latest cache payload (cached or network) and rethrows the
|
||||
|
||||
Reference in New Issue
Block a user