HarmonyOS APP开发—"壁纸控"壁纸App,需要用到这个库

想做一个壁纸 App,几百张高清大图瀑布流加载?不缓存等于每次重新下载,不做降采样 4K 图直接 OOM——@ohos/imageknife 的二级缓存 + 降采样 + 生命周期管理,让瀑布流丝滑到底。

📦 仓库地址:https://gitcode.com/CPF-ApplicationTPC/ImageKnife | 安装:ohpm install @ohos/imageknife


写在前面

“壁纸控"的核心挑战是"图片多、图片大”:

  • 瀑布流一次加载几十张 4K 壁纸,不缓存 = 每次重新下载 = 流量爆炸
  • 4K 图直接解码进内存 = 单张 30MB+ = 几张就 OOM
  • 用户快速滑动,已滑出的图片请求还在跑 = 浪费资源

@ohos/imageknife 基于 Glide 思路,提供了完整的解决方案:内存 LRU 缓存 + 磁盘二级缓存 + 内存降采样 + 生命周期感知

⚠️ ImageKnife 已停止演进,新项目推荐 imageknifepro。本文仍适用于维护中的存量项目。

这篇文章聊什么

  1. 瀑布流加载——WaterFlow + ImageKnife 组件
  2. 缓存策略——内存缓存 + 磁盘缓存 + 降采样
  3. 预加载——下一条壁纸提前拉进缓存

瀑布流滑动

请求壁纸 URL

内存缓存命中?

直接渲染

磁盘缓存命中?

磁盘读取+解码

网络下载

降采样解码

存入磁盘缓存

存入内存缓存


第一步:安装

ohpm install @ohos/imageknife

需要图片变换(模糊、亮度等)时额外装:ohpm install @ohos/gpu_transform


第二步:瀑布流加载壁纸

import { ImageKnife, ImageKnifeOption, ImageKnifeComponent } from '@ohos/imageknife'

@Entry
@Component
struct WallpaperPage {
  @State wallpapers: string[] = [
    'https://cdn.example.com/wallpaper/4k_001.jpg',
    'https://cdn.example.com/wallpaper/4k_002.jpg',
    'https://cdn.example.com/wallpaper/4k_003.jpg',
    // ... 更多壁纸
  ]

  aboutToAppear() {
    // 配置内存缓存 100MB
    ImageKnife.with().initMemoryCache(100 * 1024 * 1024)
  }

  build() {
    WaterFlow() {
      ForEach(this.wallpapers, (url: string) => {
        FlowItem() {
          ImageKnifeComponent({
            imageKnifeOption: {
              loaderSource: { uri: url },
              placeholder: $r('app.media.placeholder'),
              errorholder: $r('app.media.error'),
              // 降采样:按目标尺寸采样,4K 图不会全量进内存
              downsampleOf: 'smallest',
            }
          })
            .width('100%')
            .aspectRatio(0.6)
        }
      }, (url: string) => url)
    }
    .columnsTemplate('1fr 1fr')
    .width('100%').height('100%')
  }
}

降采样是"壁纸控"不 OOM 的关键——4K 图按显示尺寸(约 300px 宽)采样后,内存从 30MB 降到几百 KB


第三步:下载进度 + 仅缓存加载

// 带下载进度
ImageKnifeComponent({
  imageKnifeOption: {
    loaderSource: { uri: url },
    onProgressUpdate: (received, total) => {
      console.info(`下载进度: ${Math.ceil(received / total * 100)}%`)
    },
  }
})

// 离线模式:仅从缓存加载,不走网络
ImageKnifeComponent({
  imageKnifeOption: {
    loaderSource: { uri: url },
    onlyRetrieveFromCache: true, // 缓存没有就显示 errorholder
  }
})

第四步:预加载下一条壁纸

用户还在看第 3 张时,提前把第 4、5 张拉进缓存:

// 预加载(不显示,只进缓存)
ImageKnife.with().preLoadCache('https://cdn.example.com/wallpaper/4k_004.jpg')
ImageKnife.with().preLoadCache('https://cdn.example.com/wallpaper/4k_005.jpg')

// 用户滑到第 4 张时,内存缓存已命中,秒开

为什么"壁纸控"选了 ImageKnife?

需求 原生 Image @ohos/imageknife
内存缓存 ✅ LRU
磁盘缓存 ✅ 二级缓存
降采样 ✅ 防 OOM
下载进度 ✅ 回调
预加载 ✅ preLoadCache
生命周期感知 ✅ 销毁自动取消
离线模式 ✅ onlyRetrieveFromCache

总结

"壁纸控"这个场景里,@ohos/imageknife 解决了三件事:

  1. 不 OOM——降采样让 4K 图按显示尺寸进内存,30MB → 几百 KB
  2. 不重下——内存 + 磁盘二级缓存,滑过的图再滑回来秒开
  3. 不浪费——预加载 + 生命周期感知,该提前拉的提前拉,该取消的自动取消

如果你也在做壁纸、相册、电商商品图等海量图片场景,@ohos/imageknife 的缓存体系能让你省心一大半。(新项目建议直接用 imageknifepro)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐