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(); // 基于时间戳的随机文件名
}

提示

  • 您不必实现所有的 onAddedonAccessedonDownloaded

示例代码

以下是完整的示例代码:

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`
}
1 回复

更多关于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天
  ),
);

高级用法

自定义缓存存储路径

你可以通过 CacheStorestorePath 参数来自定义缓存存储的路径:

final cacheStore = CacheStore(storePath: '/path/to/cache');

自定义缓存键

默认情况下,flutter_cache_store 使用 URL 作为缓存键。你可以通过 keyBuilder 参数来自定义缓存键的生成方式:

final cacheStore = CacheStore(
  keyBuilder: (url) => 'custom_key_$url',
);
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!