cached_value
一种简单的方法来缓存由昂贵操作产生的值。
缓存那些
- 以一致的方式从其他值计算出来的值很有用;
- 可以根据已知和未知条件更改;
- 不应在每次访问时都进行计算(如 getter);
安装
添加到 pubspec.yaml
dependencies:
cached_value: <most recent version>
在 pub 上查找最新版本。
用法
缓存可以从简单的手动控制缓存创建,并与自动功能组合。
例如依赖关系和生存时间。
创建缓存
简单的缓存仅通过手动使之失效。
int factorial(int n) {
if (n < 0) throw ('Negative numbers are not allowed.');
return n <= 1 ? 1 : n * factorial(n - 1);
}
int originalValue = 1;
final factorialCache = CachedValue(() => factorial(originalValue));
print(factorialCache.value); // 1
originalValue = 6;
print(factorialCache.value); // 1
print(factorialCache.isValid) // true, invalid only when invalidate is called
// mark as invalid
factorialCache.invalidate();
print(factorialCache.isValid); // false
print(factorialCache.value); // 720
print(factorialCache.isValid); // true
在缓存无效时访问 value 会刷新缓存。可以通过以下方式手动刷新:refresh 方法
// ...
originalValue = 12;
factorialCache.refresh();
print(factorialCache.value); // 12
组合缓存
可以通过声明性 API 将缓存与更多资源组合。通过这样做,可以
添加 TTL 和依赖关系,而不会偏离缓存的原始行为。
示例
int factorial(int n) {
if (n < 0) throw ('Negative numbers are not allowed.');
return n <= 1 ? 1 : n * factorial(n - 1);
}
int originalValue = 1;
final fancyFactorialCache = CachedValue(
() => factorial(originalValue),
).withDependency(() => originalValue) // Add dependency
.withTimeToLive(lifetime: Duration(seconds: 4)); // Add TTL
您甚至可以通过扩展 SingleChildCachedValue 来创建自己的行为。
添加依赖
如果依赖值已更改,则将依赖缓存标记为无效。
int factorial(int n) {
if (n < 0) throw ('Negative numbers are not allowed.');
return n <= 1 ? 1 : n * factorial(n - 1);
}
int originalValue = 1;
final factorialCache = CachedValue(
() => factorial(originalValue),
).withDependency(() => originalValue);
print(factorialCache.value); // 1
print(factorialCache.isValid); // true
// update value
originalValue = 6;
print(factorialCache.isValid); // false
print(factorialCache.value); // 720
print(factorialCache.isValid); // true
⚠️重要
依赖回调会在每次访问值时调用。因此,建议保持其尽可能声明式。
// Avoid this:
final someCache = CachedValue(
// ...
).withDependency(() => someExpensiveOperation(originalValue));
添加生存时间
缓存可以在刷新后一段时间自动标记为无效。
int factorial(int n) {
if (n < 0) throw ('Negative numbers are not allowed.');
return n <= 1 ? 1 : n * factorial(n - 1);
}
int originalValue = 1;
final factorialCache = CachedValue(
() => factorial(originalValue),
).withTimeToLive(
lifetime: Duration(seconds: 3),
);
originalValue = 6;
print(factorialCache.value); // 1
await Future.delayed(Duration(seconds: 3));
print(factorialCache.value); // 720
更多文档
在 API 文档 中有更详细的文档。
动机
一些命令式 API,例如 Flutter 渲染对象上的画布绘制,或 Flame 的组件可能
受益于可以在多个帧(或绘制)之间存储和重用的值。
在一些非常具体的情况下,我发现将某些对象(如 Paint 和 TextPainter 实例)存储在帧之间非常方便。
Paint 和 TextPainter 实例。
渲染对象上的示例
class BlurredRenderObject extends RenderObject {
// ...
double _blurSigma = 0.0;
double get blurSigma => _blurSigma;
set blurSigma(double value) {
_blurSigma = blurSigma;
markNeedsPaint();
}
// ...
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
final paint = Paint()..maskFilter = MaskFilter.blur(
BlurStyle.normal, blurSigma
);
canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
}
}
可以更改为
class BlurredRenderObject extends RenderObject {
// ...
double _blurSigma = 0.0;
double get blurSigma => _blurSigma;
set blurSigma(double value) {
_blurSigma = blurSigma;
markNeedsPaint();
}
// Add cache:
late final paintCache = CachedValue(
() => Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, blurSigma),
).withDependency(() => blurSigma);
// ...
@override
void paint(PaintingContext context, Offset offset) {
final canvas = context.canvas;
// use cache:
final paint = paintCache.value;
canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
}
}