鸿蒙图片缓存(一)

移动端开发过程中图片缓存功能是必备,iOS和安卓都有相关工具库,鸿蒙系统组件本身也自带缓存功能,但是遇到复杂得逻辑功能还是需要封装图片缓存工具。

系统组件Image

  1. Image的缓存策略

Image模块提供了三级Cache机制,解码后内存图片缓存、解码前数据缓存、物理磁盘缓存。在加载图片时会逐级查找,如果在Cache中找到之前加载过的图片则提前返回对应的结果。

  1. Image组件如何配置打开和关闭缓存
  • 内存图片缓存:通过setImageCacheCount接口打开缓存,如果希望每次联网都获取最新资源,可以不设置或设置为0不缓存。
  • 磁盘缓存:磁盘缓存是默认开启的,默认值为100M,可以将setImageFileCacheSize的值设置为0关闭磁盘缓存。
  • 解码前数据缓存:通过setImageRawDataCacheSize设置内存中缓存解码前图片数据的大小上限,单位为字节,提升再次加载同源图片的加载速度。如果不设置则默认为0,不进行缓存
TypeScript 复制代码
import app, { AppResponse } from '@system.app';

@Entry
@Component
struct Home {
  url: string = '';
  aboutToAppear(): void {
    app.setImageCacheCount(6)//内存缓存数量
    app.setImageRawDataCacheSize(10 * 1024 * 1024)//10M
    app.setImageFileCacheSize(100 * 1024 * 1024) //磁盘缓存 100M
  }
  build() {
    Column() {
      Image(this.url)
    }
    .height('100%')
    .width('100%')
  }
 
}

鸿蒙官方明确:setImageCacheCount、setImageRawDataCacheSize和setImageFileCacheSize这这三个图片缓存接口灵活性不足,后续不再更新

封装图片缓存库

由于系统图片缓存不好用,尝试封装图片下载和缓存工具。下载使用多线程taskTool子线程分发下载任务,使用request.downloadFile具体执行下载。内存缓存使用使magLruCache会根据使用图片频率,自动删除使用率低的缓存内存图片。磁盘使用文件存储。

图片获取逻辑

从内存缓存中取图片,如果没有再从磁盘文件中取图片,都没有则开启现在任务下载

TypeScript 复制代码
 /**
   * 文件下载并拿到缓存返回给调用者,如果下载和图片解析失败返回链接,通过下载链接进行加载,利用系统缓存机制进行加载。
   * @param context 上下文
   * @param downloadUrl 图片地址
   * @param downloadPath 缓存地址
   * @returns 返回PixelMap 失败返回downloadUrl
   */
  downloadCachedFile(
    downloadUrl: string
  ): Promise<image.PixelMap | string> {
    return new Promise(async (resolve, _) => {
      try {
        //1、获取图片类型例如 .png/.jpg/.weep等。
        //目前不用图片类型,应为图片链接可能无任何类型信息。
        //2、获取MD5摘要
        let downloadUrlMd5 = await new Md5Util().doMd(downloadUrl)
        //3、获取图片文件名称
        let newImageFileName = this.getImageFileName(downloadUrlMd5)
        //4、拼接下载路径地址
        let downloadPath = this.dir + this.separator + newImageFileName
        //5、检测图片文件夹是否存在,否->创建
        let existedBefore = FileUtil.checkAndMkdirSync(this.dir)
        //之前存在才应该去遍历文件,然后更新文件
        if (existedBefore) {
          //判断此图片资源是否已经被缓存到了文件夹下面
          let findFileExistInFolder = await this.findFileNameInFolder(this.dir, downloadUrlMd5)
          //如果存在去更新文件名称,否则去下载
          if (findFileExistInFolder[0]) {
            newImageFileName = await this.renameOfImageByDataTime(findFileExistInFolder[1], newImageFileName)
            downloadPath = this.dir + this.separator + newImageFileName
            //加入gif判断获取缓存,名称改变,对应的缓存需要更新到缓存里面
            let type = await this.getImageType(downloadPath)
            if (this.GIF_IMAG_TYPES.includes(type)){
              const gifUri = this.URI_HEAD + downloadPath
              ImageCacheUtil.imagLruCache.put(downloadUrlMd5, gifUri)
            }
            //内存中取
            let mapCachePixMap = ImageCacheUtil.imagLruCache.get(downloadUrlMd5)
            if (mapCachePixMap) {
              resolve(mapCachePixMap)
              return
            }
            //磁盘文件中取
            let pixelMap = await this.uriOrPathConvertPixelMap(downloadPath)
            if (pixelMap) {
              ImageCacheUtil.imagLruCache.put(downloadUrlMd5, pixelMap)
              resolve(pixelMap)
              return
            }
          }
        }
        //如果图片文件夹不存在就去下载
        this.downloadFile(this.context,downloadUrlMd5, downloadUrl, downloadPath).then((resultEnd) => {
          resolve(resultEnd)
          return
        }).catch((_: BusinessError) => {
          resolve(downloadUrl)
          return
        })
      } catch (err) {
        console.error(this.TAG + `::downLoadCacheFile error message = ${err.stack?.toString()}`)
        resolve(downloadUrl)
        return
      }
    })
  }

request.downloadFile下载图片文件解析成pixMap

TypeScript 复制代码
 /**
   * 网络下载图片方法
   * @param context
   * @param downloadUrl
   * @param downloadPath
   * @returns
   */
  private async downloadFile(context: Context,downloadUrlMd5:string, downloadUrl: string,
    downloadPath: string): Promise<image.PixelMap | string> {
    return new Promise(async (resolve, reject) => {
      //6、检测文件夹大小如果大于200M,就需要删除一半的图片资源
      this.clearHalfCache(this.dir)
      request.downloadFile(context, { url: downloadUrl, filePath: downloadPath })
        .then((downloadTask: request.DownloadTask) => {
          downloadTask.on('complete', async () => {
            let type = await this.getImageType(downloadPath)
            if (this.noCatchImageType.includes(type)) {
              this.clearImageFailCache(downloadPath)
              resolve(downloadUrl);
              return
            }
            if (this.GIF_IMAG_TYPES.includes(type)) {
              const fileUri = this.URI_HEAD + downloadPath
              ImageCacheUtil.imagLruCache.put(downloadUrlMd5, fileUri)
              resolve(fileUri)
              return
            }
            let catchPixelMap = await this.uriOrPathConvertPixelMap(downloadPath);
            if (catchPixelMap) {
              ImageCacheUtil.imagLruCache.put(downloadUrlMd5, catchPixelMap)
              resolve(catchPixelMap)
              return
            }
            reject(new Error('PixelMap编码失败'));
          });
          downloadTask.on('fail', (error) => {
            console.error(this.TAG + `::downloadFile downloadTask fail error= ${error?.toString()}`)
            //下载失败需要删除本地路径,然后返回下载缓存路径
            this.clearImageFailCache(downloadPath);
            reject(new Error('图片下载失败'));
          });
        })
        .catch((err: BusinessError) => {
          console.error(`${this.TAG}::downloadFile Failed to request the download. Code: ${err.code}, message: ${err.message}`);
          this.clearImageFailCache(downloadPath);
          reject("err message:" + err.message + ",error code:" + err.code)
        });
    })
  }
相关推荐
夜影风13 小时前
Nginx反向代理与缓存实现
运维·nginx·缓存
编程(变成)小辣鸡15 小时前
Redis 知识点与应用场景
数据库·redis·缓存
菜菜子爱学习1 天前
Nginx学习笔记(八)—— Nginx缓存集成
笔记·学习·nginx·缓存·运维开发
魏波.1 天前
常用缓存软件分类及详解
缓存
yh云想1 天前
《多级缓存架构设计与实现全解析》
缓存·junit
白仑色2 天前
Redis 如何保证数据安全?
数据库·redis·缓存·集群·主从复制·哨兵·redis 管理工具
浩浩测试一下2 天前
02高级语言逻辑结构到汇编语言之逻辑结构转换 if (...) {...} else {...} 结构
汇编·数据结构·数据库·redis·安全·网络安全·缓存
ycchenG72 天前
缓存元数据损坏操作步骤(lvmcache修复)
linux·缓存
2301_793086872 天前
Redis 03 redis 缓存异常
数据库·redis·缓存
hj10433 天前
redis开启局域网访问
数据库·redis·缓存