HarmonyOS鸿蒙Next ArkTS中如何实现带缓存的图片加载(如 Glide 效果)?
HarmonyOS鸿蒙Next ArkTS中如何实现带缓存的图片加载(如 Glide 效果)? 频繁加载相同网络图片导致流量浪费和卡顿,所以实现带缓存的图片加载(如 Glide 效果),如何做呢?
鸿蒙的图片加载ImageKnife是参考开源库 Glide OpenHarmony图片加载库 还有C端实现 OpenHarmony图片加载库C端实现
更多关于HarmonyOS鸿蒙Next ArkTS中如何实现带缓存的图片加载(如 Glide 效果)?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
可以参考使用库 imageknife:
https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fimageknife
使用cacheDownload.download接口下载网络图片。
资源若下载成功会被缓存到应用内存或应用沙箱目录的特定文件中。
import { cacheDownload } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State src: string = 'https://www.example.com/xxx.gif'; // 请填写一个具体的网络图片地址。
async aboutToAppear(): Promise<void> {
// 提供缓存下载任务的配置选项。
let options: cacheDownload.CacheDownloadOptions = {};
try {
// 进行缓存下载,资源若下载成功会被缓存到应用内存或应用沙箱目录的特定文件中。
cacheDownload.download(this.src, options);
console.info(`success to download the resource. `);
} catch (err) {
console.error(`Failed to download the resource: code: ${err.code}, message: ${err.message}`);
}
}
build() {
Column() {
// 若src指定的是网络图片且已成功下载并缓存,则本次显示无需重复下载。
Image(this.src)
.width(100)
.height(100)
.objectFit(ImageFit.Cover)
.borderWidth(1)
}
.height('100%')
.width('100%')
}
}
背景知识:
1、系统自带的 Image 组件是有缓存图片功能的
2、自己实现一个三级缓存功能
问题解决:
实现三级缓存功能实例工具:
import { fileIo, fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { MD5 } from '@yunkss/eftool';
import { image } from '@kit.ImageKit';
import { FileUtils } from './FileUtils';
import { request } from '@kit.BasicServicesKit';
// 生成缓存文件名(MD5示例)
function getCacheKey(url: string): string {
return `avatar_${MD5.digest(url).getDataRow()}.jpg`; // 需自行实现MD5生成逻辑
}
// 获取缓存路径
function getCachePath(context: common.UIAbilityContext, url: string): string {
const path = `${context.cacheDir}/image`
const success = fs.accessSync(path)
if (!success) {
fs.mkdirSync(path)
}
return `${path}/${getCacheKey(url)}`;
}
// 检查文件缓存
function checkDiskCache(context: common.UIAbilityContext,
url: string,
call: (image: image.PixelMap | null) => void) {
const cachePath = getCachePath(context, url);
try {
const exists = fs.accessSync(cachePath);
if (exists) {
const imageSource = image.createImageSource(cachePath);
imageSource.createPixelMap((err: BusinessError, data: PixelMap) => {
call(data)
});
} else {
call(null)
}
} catch (err) {
console.warn('Disk cache check failed:', err);
}
}
const memoryCache = new Map<string, image.PixelMap>(); // 使用Map存储解码后图像
export function getCachedImage(context: common.UIAbilityContext,
url: string,
call: (image: image.PixelMap) => void) {
// 1. 检查内存缓存
console.log("获取图片:" + url)
if (memoryCache.has(url)) {
call(memoryCache.get(url)!);
return
}
console.log("获取磁盘获取:" + url)
// 2. 检查磁盘缓存
checkDiskCache(context, url, (diskCache) => {
if (diskCache) {
console.log("获取磁盘获取成功")
memoryCache.set(url, diskCache); // 写入内存缓存
call(diskCache);
} else {
console.log("获取网络获取:" + url)
// 3. 网络下载并缓存
downloadFile(context, url, (path: string) => {
const netSource = image.createImageSource(path);
netSource.createPixelMap((err: BusinessError, pixelMap: PixelMap) => {
// 写入内存缓存
memoryCache.set(url, pixelMap);
console.log("获取缓存中到文件:" + url)
// 异步存储到磁盘
const cachePath = getCachePath(context, url);
const imagePacker = image.createImagePacker();
const packOpts: image.PackingOption = { format: "image/jpeg", quality: 90 };
imagePacker.packing(pixelMap, packOpts,
(err: BusinessError, data: ArrayBuffer) => {
const file =
fs.openSync(cachePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.writeSync(file.fd, data);
call(pixelMap)
});
});
})
}
});
}
//网络下载图片
function downloadFile(context: common.UIAbilityContext, url: string, call: (path: string) => void) {
const cachePath = getCachePath(context, url);
const config: request.DownloadConfig = {
url: url,
filePath: cachePath
}
try {
request.downloadFile(context, config, (err: BusinessError, data: request.DownloadTask) => {
if (err) {
console.error("下载异常2:" + err.message)
return
}
data.on("complete", () => {
console.log("图片下载完成 " + cachePath)
call(cachePath)
})
})
} catch (error) {
console.error("下载异常1:" + error)
}
}
使用:
import { PreferencesUtils } from '../utils/PreferencesUtils';
import { common } from '@kit.AbilityKit';
import { image } from '@kit.ImageKit';
import { getCachedImage } from '../utils/CacheUtils';
@Entry
@Component
struct SingleTitleSolutionOne {
this.getUIContext().getHostContext() as common.UIAbilityContext
@State pixelMap: image.PixelMap | null = null
aboutToAppear() {
}
build() {
Column() {
Text('标题/Banner')
.fontSize(30)
.width('100%')
.height(200)
.backgroundColor('#66666666')
.textAlign(TextAlign.Center)
.onClick(async () => {
//获取缓存图片
getCachedImage(this.context,
'https://aisearch.cdn.bcebos.com/homepage/dashboard/ai_picture_create/01.png',
(pic: image.PixelMap) => {
this.pixelMap = pic
});
})
if (this.pixelMap) {
Image(this.pixelMap)
.width("100")
.height("100")
}
}
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
}
}
日志:
首次网络下载:

缓存获取:

本地获取:

Image 组件是带缓存策略的
- Image的缓存策略
Image模块提供了三级Cache机制,解码后内存图片缓存、解码前数据缓存、物理磁盘缓存。在加载图片时会逐级查找,如果在Cache中找到之前加载过的图片则提前返回对应的结果。
- Image组件如何配置打开和关闭缓存
- 内存图片缓存:通过setImageCacheCount接口打开缓存,如果希望每次联网都获取最新资源,可以不设置(默认为0),不进行缓存。
- 磁盘缓存:磁盘缓存是默认开启的,默认值为100M,可以将setImageFileCacheSize的值设置为0关闭磁盘缓存。
- 解码前数据缓存:通过setImageRawDataCacheSize设置内存中缓存解码前图片数据的大小上限,单位为字节,提升再次加载同源图片的加载速度。如果不设置则默认为0,不进行缓存。
setImageCacheCount、setImageRawDataCacheSize和setImageFileCacheSize这三个图片缓存接口灵活性不足,后续不再演进。
对于复杂情况,需要更灵活的控制缓存策略,建议使用ImageKnife 或 imageknifepro。
在ArkTS中实现带缓存的图片加载,可使用Image组件配合资源管理器。系统内置了缓存机制,加载网络图片时会自动缓存。
对于更复杂的缓存控制,可通过ResourceManager访问缓存数据,或使用http模块下载图片后存储至应用沙箱,再通过Image组件加载本地路径。
注意:鸿蒙Next的ArkTS不支持直接使用Android的Glide库。
在HarmonyOS Next的ArkTS中,可以通过Image组件结合资源管理机制实现带缓存的图片加载,达到类似Glide的效果。核心是利用系统的缓存策略和异步加载能力。
主要实现方案:
-
使用
Image组件并设置网络源:Image(src: string)直接传入网络URL时,系统会自动管理内存缓存。
-
配置缓存策略: 通过
Image的interpolation和renderMode属性可以间接影响缓存行为,但更关键的缓存控制需要通过资源管理器。 -
自定义缓存层(推荐):
- 使用
@ohos.file.fs模块实现磁盘缓存 - 使用
LRUCache实现内存缓存 - 结合
TaskPool实现异步加载
- 使用
示例代码结构:
// 1. 定义缓存管理器
class ImageCacheManager {
private memoryCache: LRUCache<string, image.PixelMap>
private diskCachePath: string
async load(url: string): Promise<image.PixelMap> {
// 检查内存缓存
// 检查磁盘缓存
// 网络下载并缓存
}
}
// 2. 在UI中使用
@State cachedImage: PixelMap | null = null
async loadImage() {
this.cachedImage = await ImageCacheManager.load(url)
}
build() {
Image(this.cachedImage)
}
关键优化点:
- 使用
image.createImageSource处理网络图片 - 通过
imageSource.createPixelMap解码图片 - 利用
TaskPool执行耗时操作避免阻塞UI
系统级的Image组件已经内置了基础的内存缓存,对于大多数场景足够使用。需要高级功能时可扩展自定义缓存层。


