Flutter内存缓存管理插件lru_memory_cache的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter内存缓存管理插件lru_memory_cache的使用

LRU缓存

LRUCache是一个Dart库,提供了用于内存数据存储的最近最少使用(LRU)缓存机制。它通过有效地管理频繁访问项的存储,解决了不必要的网络请求和陈旧数据持久化的问题。

问题

  1. 不必要的网络请求:从网络获取数据可能会消耗大量资源,并导致性能问题,特别是当相同的数据被频繁请求时。
  2. 陈旧数据持久化:缓存机制需要处理陈旧数据的移除,以确保缓存保持相关性和最新状态。

解决方案

LRUCache通过在内存中缓存数据来减少冗余的网络请求。它提供了为每个项目设置过期时间的功能,允许自动移除陈旧数据。

使用方法

LRUCache使用一个链式哈希映射来存储数据,并使用栈来跟踪最近使用的项目。

你可以向缓存中添加和获取项目。当你添加一个项目时,可以设置项目的过期时间。一旦日期过期,该项目将从缓存中移除。该项目会成为最近使用的项目。

当你访问一个项目时,该项目会变成最近使用的项目,其他项目会被推到栈的底部。

import 'package:lru_memory_cache/lru_memory_cache.dart';

LRUMemoryCache<String, int> cache = LRUMemoryCache(
    generateKey: (k) => k.toString(),
    capacity: 5,
    expireMode: ExpireMode.autoExpire,
    autoExpireCheckDuration: Duration(seconds: 1),
    onExpire: (key, item) {
      print("$item is expiring");
      return true;
    },
    shouldRemoveOnCapacity: (key, item) {
      print("Deciding to remove $item");
      return item % 2 == 0;
    },
    onCapacityRemoved: (key, item) {
      print("$item was removed due to capacity");
    },
);

// 向缓存中添加项目
cache.add('key1', value: 42);
cache.add('key2', value: 87, expiryDuration: Duration(hours: 1));

// 从缓存中获取项目
int? result = cache.get('key1');

// 从缓存中获取多个项目
ManyResult<String, int> manyResult = cache.getMany(['key1', 'key2']);

// 完成后释放缓存
cache.dispose();

特性

动态容量

你可以根据应用程序的需求动态设置缓存的容量。

项目过期

设置项目在内存中保留的时间。此功能特别适用于处理频繁变化的数据。

项目持久性

可以选择使项目在缓存中持久存在,即使它已过期或是最少使用的项目。

过期模式

选择两种方式之一来移除过期项目:

  1. 自动过期:根据指定的持续时间自动移除项目。
  2. 交互时过期:仅在与缓存交互时(例如添加或检索项目时)移除项目。

全局过期时间

设置所有项目默认的过期时间,当未定义特定过期时间时使用。

API

LRUMemoryCache

LRUMemoryCache<K, V>({
  required K Function(V data) generateKey,
  int capacity = 100,
  Duration? autoExpireCheckDuration,
  Duration? globalExpiryTime,
  bool Function(K, V)? onExpire,
  void Function(K, V)? onCapacityRemoved,
  bool Function(K, V)? shouldRemoveOnCapacity,
  ExpireMode expireMode = ExpireMode.onInteraction,
  bool Function(K, K)? equals,
  int Function(K)? hashCode,
  bool Function(dynamic)? isValidKey,
})
  • generateKey: 从值生成键的函数。
  • capacity: 缓存的最大容量(默认:100)。
  • autoExpireCheckDuration: 自动过期检查的持续时间(如果expireModeExpireMode.autoExpire则必需)。
  • globalExpiryTime: 当未定义特定过期时间时,默认的项目过期时间。
  • onExpire: 在项目过期前触发的回调函数。
  • onCapacityRemoved: 当项目因达到容量而移除时触发的回调函数。
  • shouldRemoveOnCapacity: 在达到容量时决定是否移除项目的回调函数。
  • expireMode: 移除过期项目的选项(ExpireMode.autoExpireExpireMode.onInteraction)。
  • equals: 用于键比较的自定义相等函数。
  • hashCode: 用于键散列的自定义哈希函数。
  • isValidKey: 用于检查键是否有效的自定义函数。

属性

  • isAtCapacity: 如果缓存达到其容量,则返回true。
  • isNotAtCapacity: 如果缓存还有空间添加更多项目,则返回true。
  • capacity: 获取或设置当前缓存的容量。

方法

  • add: 添加具有可选过期持续时间的值到缓存。
  • addMany: 添加多个具有可选过期持续时间的值到缓存。
  • get: 通过键检索缓存中的值。
  • getMany: 通过键检索多个缓存中的值。
  • dispose: 清除缓存并停止自动过期计时器。

ExpireMode 枚举

定义了如何移除过期项目的选项:

  1. autoExpire: 根据指定的持续时间自动过期项目。
  2. onInteraction: 仅在与缓存交互时(例如添加或检索项目时)过期项目。

ManyResult 类

getMany方法返回的结果类,包含找到和未找到的项目。

确保generateKeyFunction提供唯一的键,否则它们将被覆盖

import 'dart:async';

import 'package:lru_memory_cache/lru_memory_cache.dart';

Future<void> main() async {
  LRUMemoryCache<String, int> cache = LRUMemoryCache(
    generateKey: (k) => k.toString(),
    capacity: 5,
    expireMode: ExpireMode.onInteraction,
    autoExpireCheckDuration: Duration(seconds: 1),
    onExpire: (key, item) {
      print("$item is expiring");
      return true;
    },
    shouldRemoveOnCapacity: (key, item) {
      print("Deciding to remove $item");
      return item % 2 == 0;
    },
    onCapacityRemoved: (key, item) {
      print("$item was removed due to capacity");
    },
  );

  var list = List.generate(10, (index) => index + 1);

  for (var r in list) {
    cache.add(
      r,
      // expiryDuration: Duration(seconds: 5),
    );
  }

  print(cache.data);

  // Deciding to remove 1
  // Deciding to remove 2
  // 2 was removed due to capacity
  // Deciding to remove 1
  // Deciding to remove 3
  // Deciding to remove 4
  // 4 was removed due to capacity
  // Deciding to remove 1
  // Deciding to remove 3
  // Deciding to remove 5
  // Deciding to remove 6
  // 6 was removed due to capacity
  // Deciding to remove 1
  // Deciding to remove 3
  // Deciding to remove 5
  // Deciding to remove 7
  // Deciding to remove 8
  // 8 was removed due to capacity
  // Deciding to remove 1
  // Deciding to remove 3
  // Deciding to remove 5
  // Deciding to remove 7
  // Deciding to remove 9
  // 1 was removed due to capacity
  // [10, 9, 7, 5, 3]
}

更多关于Flutter内存缓存管理插件lru_memory_cache的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter内存缓存管理插件lru_memory_cache的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用lru_memory_cache插件进行内存缓存管理的示例代码。lru_memory_cache是一个用于实现LRU(Least Recently Used,最近最少使用)缓存策略的Flutter插件。

首先,你需要在你的pubspec.yaml文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  lru_cache: ^2.0.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

接下来是一个完整的示例,展示了如何使用lru_memory_cache来缓存图像数据:

import 'package:flutter/material.dart';
import 'package:lru_cache/lru_cache.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:convert';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'LRU Memory Cache Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final LruCache<String, Uint8List> cache = LruCache<String, Uint8List>(
    capacity: 10, // 设置缓存容量
  );

  Future<Uint8List?> _loadImage(String url) async {
    // 先检查缓存
    if (cache.containsKey(url)) {
      print("Image loaded from cache");
      return cache[url]!;
    } else {
      // 模拟网络加载图像数据
      print("Loading image from network");
      await Future.delayed(Duration(seconds: 2)); // 模拟网络延迟
      // 这里你应该通过网络请求获取图像数据,这里只是示例
      // 例如使用http.get(Uri.parse(url)).then((response) => response.bodyBytes)
      final Uint8List imageData = Uint8List.fromList(utf8.encode("Fake Image Data"));
      // 将图像数据存入缓存
      cache[url] = imageData;
      return imageData;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('LRU Memory Cache Example'),
      ),
      body: Center(
        child: FutureBuilder<Uint8List?>(
          future: _loadImage('https://example.com/image.png'), // 替换为实际的图像URL
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return CircularProgressIndicator();
            } else if (snapshot.hasError) {
              return Text('Error loading image');
            } else if (snapshot.hasData) {
              final Uint8List? imageData = snapshot.data;
              return Image.memory(imageData!);
            } else {
              return Text('No image data');
            }
          },
        ),
      ),
    );
  }
}

代码解释:

  1. 依赖安装:在pubspec.yaml文件中添加lru_cache依赖。
  2. 缓存初始化:在_MyHomePageState类中,初始化一个LruCache实例,并设置容量为10。
  3. 加载图像数据_loadImage方法首先检查缓存中是否已有图像数据,如果有则直接返回;如果没有,则模拟网络加载图像数据,并将其存入缓存。
  4. 显示图像:在build方法中使用FutureBuilder来异步加载和显示图像。

注意:

  • 示例中的图像数据是通过Uint8List.fromList(utf8.encode("Fake Image Data"))模拟的,实际开发中应通过HTTP请求获取真实的图像数据。
  • 缓存的容量(capacity)应根据实际需求进行调整。
  • 示例代码省略了实际的网络请求部分,你可以使用httpdio等Flutter网络请求库来获取图像数据。

这样,你就可以在Flutter项目中利用lru_memory_cache插件实现内存缓存管理了。

回到顶部