Flutter数据缓存插件flutter_cache_store的使用
Flutter数据缓存插件flutter_cache_store的使用
flutter_cache_store简介
flutter_cache_store 是一个灵活的缓存管理器,适用于 Flutter 应用。该插件受到 flutter_cache_manager 的启发,可以轻松地在两者之间切换。
快速开始
以下是一个简单的示例,展示如何使用 flutter_cache_store 获取文件并进行缓存:
import 'package:flutter_cache_store/flutter_cache_store.dart';
void demo(String url) async {
final store = await CacheStore.getInstance();
final file = await store.getFile(url);
// 对文件进行操作...
}
APIs
CacheStore
以下是 CacheStore 的基本使用方法:
void api() async {
// 获取存储实例
CacheStore store = await CacheStore.getInstance(
namespace: 'unique_name', // 默认为 null - 有效的文件名作为唯一ID
policy: LeastFrequentlyUsedPolicy(), // 默认为 null - 将使用 `LessRecentlyUsedPolicy()`
clearNow: true, // 默认为 false - 是否立即清理
fetch: myFetch, // 默认为 null - `CacheStore.fetch` 的快捷方式
);
// 可以随时更改自定义的 fetch 方法。
// 设置为 `null` 将简单地使用 `http.get`
store.fetch = myFetch;
// 从URL获取文件并缓存
File file = await store.getFile(
'url', // GET 方法
key: null, // 使用自定义字符串代替URL
headers: {}, // 与 http.get 相同
fetch: myFetch, // 可选: 自定义请求函数
// 可选: Map<String, dynamic> 任何你想要传递给自定义 fetch 函数的内容
custom: {'method': 'POST', 'body': 'test'},
flushCache: false, // 是否重新下载文件
);
// 按键刷新特定文件
await store.flush([
'key', // 键(默认为URL)传递给 `getFile`
]);
// 删除所有缓存文件
await store.clearAll();
}
// 自定义 fetch 函数。
// 示例:如何实现支持 POST 和 body 的 fetch
Future<Response> myFetch(url,
{Map<String, String> headers, Map<String, dynamic> custom}) {
final data = custom ?? {};
switch (data['method'] ?? '') {
case 'POST':
{
return post(url, headers: headers, body: data['body']);
}
default:
return get(url, headers: headers);
}
}
缓存文件结构
默认情况下,缓存文件将保存在 <$TEMP>/cache_store
中。<$TEMP>
是由 path_provider
生成的。默认的临时文件名是基于时间戳的11个字符。
可以通过覆盖 Policy 来自定义 <$TEMP>/cache_store
下的文件结构。例如:
// 假设您正在开发一款小说阅读器应用,并且您的应用会缓存书籍章节。
// 您的 API 返回一些书籍和章节的ID,ID只包含字母和数字。
class LRUCachePolicy extends LessRecentlyUsedPolicy {
LRUCachePolicy({int maxCount}) : super(maxCount: maxCount);
[@override](/user/override)
String generateFilename({final String key, final String url}) =>
key; // 使用 key 作为文件名
}
void customizedCacheFileStructure() async {
// 获取存储实例
CacheStore store = await CacheStore.getInstance(
policy: LRUCachePolicy(maxCount: 4096),
namespace: 'my_store',
);
// 从URL获取文件并缓存
String bookId = 'book123';
String chapterId = 'ch42';
String chapterUrl = 'https://example.com/book123/ch42';
File file = await store.getFile(
chapterUrl,
key: '$bookId/$chapterId', // 使用ID作为路径和文件名
);
// 文件将被缓存在 `$TEMP/cache_store__my_store/book123/ch42`
}
缓存策略
LessRecentlyUsedPolicy
LRU 策略。当达到 maxCount
时,最近最少使用的文件将被移除。每次访问文件时都会更新其使用时间戳。
new LessRecentlyUsedPolicy(
maxCount: 999,
);
LeastFrequentlyUsedPolicy
LFU 策略。当达到 maxCount
时,使用频率最低的文件将被移除。每次访问文件时都会增加其命中次数。在 hitAge
时间后命中次数将过期。如果文件具有相同的命中次数,则回退到 LRU 策略。
new LeastFrequentlyUsedPolicy(
maxCount: 999,
hitAge: Duration(days: 30),
);
CacheControlPolicy
Cache-Control
头部策略。此策略通常遵循 HTTP 响应头 Cache-Control
的 <max-age>=<seconds>
或 <s-maxage>=<seconds>
规则。如果没有设置 max-age-seconds
,它将使用 minAge
,除非将其设置为 null
。年龄不会超过 maxAge
。
new CacheControlPolicy(
maxCount: 999,
minAge: Duration(seconds: 30), // 可空
maxAge: Duration(days: 30), // 可空
);
FifoPolicy
先进先出策略,非常简单,可能仅用于示例。
new FifoPolicy(
maxCount: 999,
);
性能警告
实现注意事项
- 该实现维护了所有 key-item 在内存中以提高速度。因此,
maxCount
必须在 1 到 100000(100k)之间,以避免内存和文件系统的成本过高。 - 当前,所有策略只是简单地对所有项目进行排序以过期文件。这可能会由于
O(N*logN)
的复杂性而影响性能。
改进方向
- 将切换到优先队列,其复杂度为
O(N*logK)
,其中K
通常是一个很小的数字。
如何实现自己的策略
接口是一个简单的抽象类。您只需要实现几个方法。
abstract class CacheStorePolicy {
// 这是你必须实现的唯一方法。
// `store` 将从时间到时间调用此方法。
// 确保一次性返回所有过期项。
// 然后 `store` 将负责移除缓存文件。
// 如果需要持久化某些数据,您还需要保存它们。
Future<Iterable<CacheItem>> cleanup(Iterable<CacheItem> allItems);
// 当调用 store.clearAll 时将被调用。
Future<void> clearAll(Iterable<CacheItem> allItems) async {}
// 当创建 `store` 时只调用一次,并加载保存的数据。
// 您需要加载持久化数据并恢复项目的有效负载。
// 只有返回的项目将被缓存。其他项目将在稍后回收。
Future<Iterable<CacheItem>> restore(List<CacheItem> allItems) async => allItems;
// 当新 `CacheItem` 添加到缓存时触发。
// 您可能需要附加一个 `CacheItemPayload` 实例。
Future<void> onAdded(final CacheItem addedItem) async {}
// 当项目刚刚被访问时触发。
// 您可能需要附加或更新项目的有效负载。
Future<void> onAccessed(final CacheItem accessedItem, bool flushed) async {}
// 当请求完成时触发。
// 响应头也会被传递。
Future<void> onDownloaded(final CacheItem item, final Map<String, String> headers) async {}
// 当调用 `store.flush` 时触发。
Future<void> onFlushed(final Iterable<CacheItem> flushedItems) async {}
// 文件名(包括路径)相对于 `CacheItem.rootPath`。
// 通常忽略此选项,除非需要更好的文件结构。
// 您必须提供有效的文件名。
String generateFilename({final String key, final String url}) =>
Utils.genName(); // 基于时间戳的随机文件名
}
提示
- 您不必实现所有的
onAdded
、onAccessed
和onDownloaded
。
示例代码
以下是完整的示例代码:
import 'dart:io';
import 'package:flutter_cache_store/flutter_cache_store.dart';
import 'package:http/http.dart' show Response, get, post;
// [GET STARTED]
void demo(String url) async {
final store = await CacheStore.getInstance();
final file = await store.getFile(url);
// 对文件进行操作...
}
// [BASIC OPTIONS]
void api() async {
// 获取存储实例
CacheStore store = await CacheStore.getInstance(
namespace:
'unique_name', // 默认为 null - 有效的文件名作为唯一ID
policy: LeastFrequentlyUsedPolicy(), // 默认为 null - 将使用 `LessRecentlyUsedPolicy()`
clearNow: true, // 默认为 false - 是否立即清理
fetch: myFetch, // 默认为 null - `CacheStore.fetch` 的快捷方式
);
// 可以随时更改自定义 fetch 方法。
// 设置为 `null` 将简单地使用 `http.get`
store.fetch = myFetch;
// 从URL获取文件并缓存
File file = await store.getFile(
'url', // GET 方法
key: null, // 使用自定义字符串代替URL
headers: {}, // 与 http.get 相同
fetch: myFetch, // 可选: 自定义请求函数
// 可选: Map<String, dynamic> 任何你想要传递给自定义 fetch 函数的内容
custom: {'method': 'POST', 'body': 'test'},
flushCache: false, // 是否重新下载文件
);
// 按键刷新特定文件
await store.flush([
'key', // 键(默认为URL)传递给 `getFile`
]);
// 删除所有缓存文件
await store.clearAll();
}
// 自定义 fetch 函数。
// 示例:如何实现支持 POST 和 body 的 fetch
Future<Response> myFetch(url,
{Map<String, String> headers, Map<String, dynamic> custom}) {
final data = custom ?? {};
switch (data['method'] ?? '') {
case 'POST':
{
return post(url, headers: headers, body: data['body']);
}
default:
return get(url, headers: headers);
}
}
// [ADVANCED USAGE]
// 扩展 Policy 类并重写 `generateFilename`
class LRUCachePolicy extends LessRecentlyUsedPolicy {
LRUCachePolicy({int maxCount}) : super(maxCount: maxCount);
[@override](/user/override)
String generateFilename({final String key, final String url}) =>
key; // 使用 key 作为文件名
}
void customizedCacheFileStructure() async {
// 获取存储实例
CacheStore store = await CacheStore.getInstance(
policy: LRUCachePolicy(maxCount: 4096),
namespace: 'my_store',
);
// 从URL获取文件并缓存
String bookId = 'book123';
String chapterId = 'ch42';
String chapterUrl = 'https://example.com/book123/ch42';
File file = await store.getFile(
chapterUrl,
key: '$bookId/$chapterId', // 使用ID作为路径和文件名
);
// 文件将被缓存在 `$TEMP/cache_store__my_store/book123/ch42`
}
更多关于Flutter数据缓存插件flutter_cache_store的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_cache_store
是一个用于 Flutter 应用的数据缓存插件,它可以帮助你轻松地管理网络请求的缓存数据。通过使用这个插件,你可以减少重复的网络请求,提高应用的性能,并在离线状态下仍然能够访问之前缓存的数据。
安装
首先,你需要在 pubspec.yaml
文件中添加 flutter_cache_store
依赖:
dependencies:
flutter:
sdk: flutter
flutter_cache_store: ^1.0.0
然后运行 flutter pub get
来安装依赖。
基本用法
1. 初始化缓存存储
在使用 flutter_cache_store
之前,你需要初始化一个 CacheStore
实例。通常你可以在应用的 main
函数中进行初始化:
import 'package:flutter_cache_store/flutter_cache_store.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化缓存存储
final cacheStore = CacheStore();
runApp(MyApp());
}
2. 缓存数据
你可以使用 cacheStore.get
方法来获取缓存数据。如果缓存中不存在数据,它会自动从网络请求数据并缓存起来。
import 'package:flutter/material.dart';
import 'package:flutter_cache_store/flutter_cache_store.dart';
class MyApp extends StatelessWidget {
final CacheStore cacheStore = CacheStore();
Future<String> fetchData() async {
final url = 'https://jsonplaceholder.typicode.com/posts/1';
final response = await cacheStore.get(url);
return response.body;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Cache Store Example'),
),
body: FutureBuilder<String>(
future: fetchData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return Center(child: Text('Data: ${snapshot.data}'));
}
},
),
),
);
}
}
3. 清除缓存
你可以使用 cacheStore.clear
方法来清除缓存中的所有数据:
cacheStore.clear();
4. 删除特定缓存
如果你只想删除特定的缓存数据,可以使用 cacheStore.delete
方法:
final url = 'https://jsonplaceholder.typicode.com/posts/1';
cacheStore.delete(url);
5. 设置缓存策略
你可以通过 CachePolicy
来设置缓存策略,例如设置缓存的最大大小、缓存的有效期等。
final cacheStore = CacheStore(
policy: CachePolicy(
maxSize: 100 * 1024 * 1024, // 100 MB
maxAge: Duration(days: 7), // 缓存有效期为7天
),
);
高级用法
自定义缓存存储路径
你可以通过 CacheStore
的 storePath
参数来自定义缓存存储的路径:
final cacheStore = CacheStore(storePath: '/path/to/cache');
自定义缓存键
默认情况下,flutter_cache_store
使用 URL 作为缓存键。你可以通过 keyBuilder
参数来自定义缓存键的生成方式:
final cacheStore = CacheStore(
keyBuilder: (url) => 'custom_key_$url',
);