鸿蒙应用如何实现内存级别全局缓存数据?

鸿蒙应用如何实现内存级别全局缓存数据?

一、结论:

该问题首先需要搞清楚,全局缓存的数据,是内存级别缓存,即数据只存在App运行期间。还是持久化级别,即数据在App关闭再重新打开,依旧可以获取。

1、首先内存级别:

可以使用(1)AppStorage(2)单例管理(3)LRUCache管理。

2、其次持久化级别:

(1)PersistentStorage(2)Preferences 首选项(3)以及关系型数据库。

二、代码实现和详细解释:

1、首先内存级别:
(1)AppStorage

typescript 复制代码
// 存储数据
AppStorage.SetOrCreate<string>('userToken', 'abc123');

// 获取数据
let token: string = AppStorage.Get<string>('userToken');

// 组件内使用(自动绑定)
@Entry
@Component
struct UserInfo {
  @StorageLink('userToken') token: string = 'test';

  build() {
    Text(`Token: ${this.token}`)
  }
}

(2)单例管理

GlobalCacheMgr 示例:

typescript 复制代码
export class GlobalCacheMgr {
  // 移除多余空格,规范类型声明
  private static mGlobalCacheMgr: GlobalCacheMgr;
  private cacheMap: Map<string, Object> = new Map();

  public static Ins(): GlobalCacheMgr {
    if (!GlobalCacheMgr.mGlobalCacheMgr) {
      GlobalCacheMgr.mGlobalCacheMgr = new GlobalCacheMgr();
    }
    return GlobalCacheMgr.mGlobalCacheMgr;
  }
  
  // 存储数据
  set(key: string, value: Object): void {
    this.cacheMap.set(key, value);
  }

  // 获取数据:泛型推导更安全,避免强制类型断言的风险
  get<T>(key: string): T | undefined {
    const value = this.cacheMap.get(key);
    return value as T | undefined;
  }

  // 增加缓存清理方法,避免内存泄漏
  clear(key?: string): void {
    if (key) {
      this.cacheMap.delete(key);
    } else {
      this.cacheMap.clear();
    }
  }
  
}

调用示例:

typescript 复制代码
import { GlobalCacheMgr } from '../mgr/GlobalCacheMgr';

/**
 * 全局缓存单例管理类 测试页面
 */
@Entry
@Component
struct GlobalCacheMgrTestPage {
  private TAG: string = "ContactPage";

  private onClickTest = () => {
    let key: string = "userToken";
    GlobalCacheMgr.Ins().set(key, "test");
    let result: string | undefined = GlobalCacheMgr.Ins().get(key);
    console.log(this.TAG, " onClickTest result: " + result);
  }

  build() {
    Row() {
      Button('点击测试全局缓存')
        .onClick(this.onClickTest)
    }
    .justifyContent(FlexAlign.Center)
    .size({
      width: "100%",
      height: "100%"
    })
  }
}

(3)LRUCache管理

LRUCache在图片缓存中使用最多,采用链表的方式,设置最大值,每次填入数据,通过key去判断,如果有,且没有达到最大值,则更新。如果达到最大值,则删除最头部的数据。保证高频数据的缓存,减轻内存的压力。

LRUCacheMgr 管理类示例:

typescript 复制代码
import { util } from '@kit.ArkTS';

/**
 * LRU缓存工具类(单例模式)
 * 基于HarmonyOS内置util.LRUCache实现,采用LRU(最近最少使用)淘汰策略
 * 当缓存数量达到容量上限时,自动移除最久未使用的缓存项
 */
export class LRUCacheMgr {
  // 单例实例(全局唯一)
  private static instance: LRUCacheMgr;
  // LRU缓存核心实例:键为string类型,值为任意Object类型
  private lruCache: util.LRUCache<string, Object>;
  // 初始最大缓存容量(测试用,默认5个缓存项)
  private MAX_NUM: number = 5;

  /**
   * 私有构造函数
   * 禁止外部通过new关键字实例化,保证单例特性
   * 初始化LRUCache并设置初始最大容量
   */
  private constructor() {
    this.lruCache = new util.LRUCache(this.MAX_NUM);
  }

  /**
   * LRUCacheMgr(懒汉式初始化)
   * 首次调用时创建实例,后续调用返回已创建的实例
   * @returns LRUCacheMgr 全局唯一的单例对象
   */
  public static getInstance(): LRUCacheMgr {
    if (!LRUCacheMgr.instance) {
      LRUCacheMgr.instance = new LRUCacheMgr();
    }
    return LRUCacheMgr.instance;
  }

  /**
   * 判断LRU缓存是否为空
   * @returns boolean - true:缓存为空;false:缓存非空
   */
  public isEmpty(): boolean {
    return this.lruCache.isEmpty();
  }

  /**
   * 获取LRU缓存的当前最大容量(可存储的缓存项数量上限)
   * @returns number 缓存容量值
   */
  public getCapacity(): number {
    return this.lruCache.getCapacity();
  }

  /**
   * 重置/更新LRU缓存的最大容量
   * @param newCapacity 新的缓存容量(需传入大于0的数字)
   */
  public updateCapacity(newCapacity: number) {
    this.lruCache.updateCapacity(newCapacity);
  }

  /**
   * 向LRU缓存中添加/更新缓存项
   * 若key已存在,会覆盖原有值;若容量已满,会淘汰最久未使用的缓存项
   * @param key 缓存键(唯一标识,字符串类型)
   * @param value 缓存值(任意Object类型,如字符串、对象、数字等)
   */
  public putCache(key: string, value: Object) {
    this.lruCache.put(key, value);
  }

  /**
   * 删除指定key对应的缓存项
   * 若key不存在,该操作无效果
   * @param key 要删除的缓存键
   */
  public remove(key: string) {
    this.lruCache.remove(key);
  }

  /**
   * 获取指定key对应的缓存值
   * @param key 缓存键
   * @returns Object | undefined - 存在则返回缓存值,不存在则返回undefined
   */
  public getCache(key: string): Object | undefined {
    return this.lruCache.get(key);
  }

  /**
   * 判断缓存中是否包含指定key的缓存项
   * @param key 缓存键
   * @returns boolean - true:存在;false:不存在
   */
  public contains(key: string): boolean {
    return this.lruCache.contains(key);
  }

  /**
   * 清空所有缓存数据,并将缓存容量重置为64
   */
  public clearCache() {
    this.lruCache.clear(); // 清空缓存内容
    this.lruCache.updateCapacity(64); // 重置缓存容量
  }
}

调用示例:

typescript 复制代码
import { LRUCacheMgr } from '../mgr/LRUCacheMgr';


export class TestInfo{
  id: number = 0;
  name: string = "";
  age: number = 0;
}
/**
 * LRU缓存工具类 测试页面
 */
@Entry
@Component
struct LRUCacheMgrTestPage {
  // 日志TAG,便于定位日志来源
  private TAG: string = "LRUCacheMgrTestPage";

  /**
   * 点击按钮触发LRU缓存全流程测试
   * 依次测试:初始化、添加缓存、获取缓存、判断存在性、更新容量、删除缓存、清空缓存等
   */
  private onClickTestLRU = () => {
    // 1. 获取LRU缓存单例实例
    const lruCache = LRUCacheMgr.Ins();
    console.log(this.TAG, "===== 开始测试LRU缓存 =====");

    // 2. 初始状态检查
    const isEmptyInit = lruCache.isEmpty();
    const initCapacity = lruCache.getCapacity();
    console.log(this.TAG, `初始状态 - 缓存是否为空:${isEmptyInit},初始容量:${initCapacity}`);

    // 3. 添加不同类型的缓存项
    const tokenKey = "userToken";
    const userInfoKey = "userInfo";
    const maxCountKey = "maxCount";
    lruCache.putCache(tokenKey, "hmos_987654321");
    let testInfo: TestInfo = { id: 1001, name: "鸿蒙开发者", age: 25 };
    lruCache.putCache(userInfoKey, testInfo);
    lruCache.putCache(maxCountKey, 200);
    console.log(this.TAG, "添加缓存项 - userToken/userInfo/maxCount");

    // 4. 获取缓存项并打印
    const token = lruCache.getCache(tokenKey);
    const userInfo = lruCache.getCache(userInfoKey);
    const maxCount = lruCache.getCache(maxCountKey);
    console.log(this.TAG, `获取缓存 - ${tokenKey}: ${token}`);
    console.log(this.TAG, `获取缓存 - ${userInfoKey}: ${JSON.stringify(userInfo)}`);
    console.log(this.TAG, `获取缓存 - ${maxCountKey}: ${maxCount}`);

    // 5. 判断缓存项是否存在
    const hasUserInfo = lruCache.contains(userInfoKey);
    const hasInvalidKey = lruCache.contains("invalidKey");
    console.log(this.TAG, `判断存在性 - ${userInfoKey}存在:${hasUserInfo},invalidKey存在:${hasInvalidKey}`);

    // 6. 更新缓存容量
    const newCapacity = 10;
    lruCache.updateCapacity(newCapacity);
    const updatedCapacity = lruCache.getCapacity();
    console.log(this.TAG, `更新容量 - 原容量${initCapacity} → 新容量${updatedCapacity}`);

    // 7. 删除指定缓存项
    lruCache.remove(maxCountKey);
    const deletedMaxCount = lruCache.getCache(maxCountKey);
    console.log(this.TAG, `删除缓存 - ${maxCountKey}:${deletedMaxCount === undefined ? "删除成功" : "删除失败"}`);

    // 8. 清空缓存并重置容量
    lruCache.clearCache();
    const isEmptyAfterClear = lruCache.isEmpty();
    const finalCapacity = lruCache.getCapacity();
    console.log(this.TAG, `清空缓存 - 缓存是否为空:${isEmptyAfterClear},重置后容量:${finalCapacity}`);

    console.log(this.TAG, "===== LRU缓存测试结束 =====");
  }

  build() {
    Row() {
      Button('点击测试LRU缓存')
        .fontSize(16)
        .padding({ left: 20, right: 20, top: 10, bottom: 10 })
        .onClick(this.onClickTestLRU)
    }
    .justifyContent(FlexAlign.Center)
    .size({
      width: "100%",
      height: "100%"
    })
  }
}

资料引用:

AppStorage 应用级变量的内存管理: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-state-management#appstorage

LRUCache 应用内存占用优化: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-memory-optimization#section1518265464211

Preferences 用户首选项:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-data-preferences#preferencesgetpreferences

相关推荐
HONG````2 小时前
鸿蒙List组件深度使用指南:从数据绑定到极致性能优化
list·harmonyos
赵得C2 小时前
智算中心的网络与存储技术:华为解决方案的深度解析
网络·华为
SuperHeroWu72 小时前
鸿蒙应用实现横竖屏切换有几种方式?注意事项有什么?
华为·harmonyos·动态·横屏·竖屏·横竖屏·静态配置
国服第二切图仔3 小时前
Electron for 鸿蒙PC项目实战案例之简单统计组件
javascript·electron·harmonyos
奔跑的露西ly3 小时前
【HarmonyOS NEXT】组件化与模块化的理解
华为·harmonyos
晚霞的不甘3 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成:从插件开发到分布式能力实战(续篇)
flutter·开源·harmonyos
晚霞的不甘3 小时前
Flutter 与开源鸿蒙(OpenHarmony)生态融合:从 UI 渲染到系统级能力调用的全链路开发范式
flutter·开源·harmonyos
花先锋队长3 小时前
华为Mate X7:高级感,从何而来?
科技·华为·智能手机·harmonyos
2***65633 小时前
华为数据中心CE系列交换机级联M-LAG配置示例
服务器·华为·php