HarmonyOS 鸿蒙Next中列表展示大图片缓存问题
HarmonyOS 鸿蒙Next中列表展示大图片缓存问题 我的需求是本地就存了好多照片,照片有几MB 的,最大也有 30 MB 。
想问一下,有没有图片组件,可以缓存这些本地图片的,在加载本地图片的时候,生成一个缩略图存起来,
每次加载的时候,只加载这个缩略图就可以了。
我也尝试了使用 imageknife [https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fimageknifepro](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fimageknifepro)
发现,他也只是遇到网络图片才缓存 。
所以, 我这个需求有没有现成的可以用呢?
更多关于HarmonyOS 鸿蒙Next中列表展示大图片缓存问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,可以采取以下方式解决:获取图片和视频缩略图
更多关于HarmonyOS 鸿蒙Next中列表展示大图片缓存问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
结合内存缓存(LRUCache)与磁盘缓存,通过压缩技术生成低分辨率缩略图
参考代码如下
通过异步任务处理大图压缩:
import { LRUCacheUtil } from '../utils/LRUCacheUtil'
import fs from '@kit.FileKit'
async function generateThumbnail(originalPath: string) {
// 1. 检查缓存是否存在
const cache = LRUCacheUtil.getInstance()
if (cache.contains(originalPath)) {
return cache.getCache(originalPath)
}
// 2. 生成缩略图
const pixelMap = await image.createImageSource(originalPath)
.createPixelMap(options)
// 3. 缓存到内存
cache.putCache(originalPath, pixelMap)
// 4. 持久化到磁盘(可选)
const cachePath = getCacheFilePath(originalPath)
await fs.copy(originalPath, cachePath)
return pixelMap
}
在List组件中按需加载:
@Component
struct ThumbnailImage {
private originalUri: string = ''
build() {
Image(this.loadImage())
.width(200)
.height(200)
.interpolation(ImageInterpolation.High) // 高质量缩放
}
async loadImage() {
return await generateThumbnail(this.originalUri)
}
}
楼主存在本地的时候就可以对图片进行压缩
参考实现步骤:
1.将图片进行压缩:通过packToFile完成重编码,实现图片压缩功能。
const imagePackerApi: image.ImagePacker = image.createImagePacker();
imagePackerApi.packToFile(imageSource, fileLoc.fd, packOpts).then(() => {
console.info('Succeeded in packing the image to file.');
})
2.预览压缩后的图片:通过fs.listFileSync获取沙箱中的文件列表,使用path得到文件的URI,存储至fileList中,通过Image进行展示。
let sandboxPath = this.context.getApplicationContext().filesDir;
let filenames = fs.listFileSync(sandboxPath);
filenames.forEach(async fileName => {
const fullPath = sandboxPath+ "/" + fileName;
const uri = fileUri.getUriFromPath(fullPath);
let stat = fs.statSync(fullPath);
this.fileList.push(new ImageItem(uri, fileName, this.formatFileSize(stat.size)))
});
您所描述的需求(为本地大图片生成并缓存缩略图以供列表展示)可以通过 getThumbnail 接口实现。getThumbnail 方法就是专门用于为图片和视频资源生成缩略图,以避免直接加载和渲染大尺寸的原文件,从而显著提升列表等场景的加载性能和流畅度。
1. 核心接口:getThumbnail
您可以在获取到媒体资源(PhotoAsset 或 FileAsset)后,调用其 getThumbnail 方法来获取缩略图。该方法有以下几种形式:
getThumbnail(callback: AsyncCallback<image.PixelMap>): voidgetThumbnail(size: image.Size, callback: AsyncCallback<image.PixelMap>): voidgetThumbnail(size?: image.Size): Promise<image.PixelMap>
关键参数:
size(可选): 您可以指定一个image.Size对象(例如{ width: 720, height: 720 }) 来设定缩略图的期望尺寸。系统会据此生成高质量且尺寸可控的缩略图。这是解决您大图片加载问题的关键。- 返回值/回调值: 返回一个
image.PixelMap对象,这是一个可以直接传递给 ArkUI 的Image组件进行显示的高效像素数据。
2. 实现步骤
您的代码逻辑大致如下:
- 获取权限:首先需要申请相册管理模块的读权限
ohos.permission.READ_IMAGEVIDEO。 - 获取管理对象:通过
photoAccessHelper.getPhotoAccessHelper(context)获取相册管理模块的实例 (phAccessHelper)。 - 查询本地图片:使用
phAccessHelper.getAssets(fetchOption)接口,配合 predicates 查询条件,获取到本地的图片资源列表 (FetchResult<PhotoAsset>)。 - 获取单张图片资源:从列表中获取单个
PhotoAsset对象。 - 生成并获取缩略图:调用
photoAsset.getThumbnail(size)方法。系统会自动处理缩略图的生成和缓存。对于同一张图片的相同尺寸请求,系统很可能会直接返回已缓存的结果,而无需再次解码原图,这极大地优化了性能。 - 显示缩略图:将返回的
PixelMap对象设置给Image组件的src属性。
// 以 Promise 模式为例,获取指定尺寸的缩略图
import { dataSharePredicates } from '@kit.ArkData';
import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
async function loadThumbnailForList(phAccessHelper: photoAccessHelper.PhotoAccessHelper, assetUri: string) {
// ... 建立查询条件,通过 uri 或其他条件获取到特定的 PhotoAsset ...
let predicates = new dataSharePredicates.DataSharePredicates();
// 假设通过 URI 定位某张图片
// predicates.equalTo(photoAccessHelper.PhotoKeys.URI, assetUri);
let fetchOption = {
fetchColumns: [],
predicates: predicates
};
try {
let fetchResult = await phAccessHelper.getAssets(fetchOption);
let photoAsset = await fetchResult.getFirstObject();
// 定义您希望在列表中显示的缩略图尺寸
let thumbnailSize: image.Size = { width: 300, height: 300 };
// 关键调用:获取缩略图。系统会处理生成和缓存。
let pixelMap: image.PixelMap = await photoAsset.getThumbnail(thumbnailSize);
// 此时您可以将 pixelMap 赋值给列表项中的 Image 组件
// this.listItemImage = pixelMap;
console.info('Thumbnail obtained successfully.');
return pixelMap;
} catch (err) {
console.error(`Failed to get thumbnail: ${err.code}, ${err.message}`);
}
}
如果列表加载的时候只加载缩略图,那直接找ui要一套就行了,当点击事件发生的时候,再去访问单独的那张原图,不然你每次启动的时候都要去对原图生成缩略图,这一步比你加载列表还卡吧
推荐
- 使用PhotoView组件+自定义缓存策略 根据搜索结果中提到的PhotoView组件(ohpm install @ohos/photoview),结合其缩放浏览能力,可扩展实现本地缩略图缓存
鸿蒙Next中列表展示大图片的内存优化方案
在鸿蒙Next中,当列表需要展示大图片时,推荐使用Image组件配合PixelMap进行内存优化。
实现步骤
-
创建图像源
- 使用
ImageSource.createImageSourceAsync方法创建图像源
- 使用
-
生成PixelMap对象
- 调用
createPixelMap方法生成缩放后的PixelMap对象
- 调用
-
图片尺寸处理
- 加载大尺寸图片前应先获取原图尺寸
- 根据列表项显示区域计算合适的采样率
-
性能优化
- 结合
LazyForEach实现按需加载 - 图片移出可视区域后自动释放资源
- 结合
这种方法可以有效管理内存使用,提升列表滚动性能。

