鸿蒙图片缓存(二)
·
缓存工具后续
上一篇中图片下载和缓存中需要注意得一点是对于动图得处理,图片如果是gif或者webp这种类型得图片,给Image组件显示得时候直接给uri,不用转换成pixMap。
//加入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)
resolve(gifUri)
return
}
获取磁盘文件转换成PixMap
/**
* 通过path和url将文件编码为pixelMap
* @param path
* @returns
*/
private async uriOrPathConvertPixelMap(path: string): Promise<image.PixelMap | undefined> {
return new Promise((resole, _) => {
try {
let file = fs.openSync(path, fs.OpenMode.READ_WRITE)
const imageSource: image.ImageSource = image.createImageSource(file.fd)
fs.close(file)
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: image.PixelMapFormat.RGBA_8888,
}
imageSource.createPixelMap(decodingOptions).then((pixelMap: PixelMap) => {
resole(pixelMap);
}).catch((_: Error) => {
resole(undefined)
});
} catch (e) {
resole(undefined)
}
})
}
图片缓存工具封装
export namespace ImageCacheUtil {
export class Builder {
imageFolderName: string = 'images'
cacheMaxSize: number = 1024 * 1024 * 200 //默认200M
context: Context
noCatchImageType: string[] = []
public constructor(context: Context) {
this.context = context
}
public setImageFolderName(imageFolderName: string): Builder{
this.imageFolderName = imageFolderName
return this
}
public setCacheMaxSize(cacheMaxSize: number): Builder{
this.cacheMaxSize = cacheMaxSize
return this
}
public setNoCatchImageType(noCatchImageType: string[]): Builder{
this.noCatchImageType.push(...noCatchImageType)
return this
}
public build(): ImageCacheUtil {
return new ImageCacheUtil(this)
}
}
}
多线程图片缓存
以上图片下载和缓存都是再主线程实现得,虽然使用了promise但是还是会抢占主线程性能,使用taskTool 多线程中下载图片增加性能。
import { ImageCacheUtil } from "./ImageCacheUtil";
import { image } from "@kit.ImageKit";
import { taskpool as TaskPool } from '@kit.ArkTS';
import { Context } from '@kit.AbilityKit';
@Concurrent
export async function downloadImage(context: Context, url: string): Promise<string | image.PixelMap> {
return await new ImageCacheUtil.Builder(context).build().downloadCachedFile(url);
}
//将线程任务添加到任务池,并执行线程操作
async function fetchImagePixelMap(context: Context, url: string): Promise<string | image.PixelMap> {
const task: TaskPool.Task = new TaskPool.Task(downloadImage, context, url);
const pixelMap = await TaskPool.execute(task)
TaskPool.terminateTask(task)
return pixelMap as (string | image.PixelMap);
}
//图片下载工具(带并发控制&&线程池)
export class ImageDownloader {
private downloadLocks: Map<string, Promise<string | image.PixelMap>> = new Map();
private static instance: ImageDownloader;
private constructor() {
}
// 获取单例实例
public static getInstance(): ImageDownloader {
if (!ImageDownloader.instance) {
ImageDownloader.instance = new ImageDownloader();
}
return ImageDownloader.instance;
}
// 清除缓存
initCheckCacheAndDeleteCache(){
new ImageCacheUtil.Builder(getContext()).build().initCheckCacheAndDeleteCache()
}
// 下载图片(带并发控制)
async downloadImage(context: Context, url: string) {
let downloadPromise = this.downloadLocks.get(url);
if (!downloadPromise) {
downloadPromise = this.executeDownload(context, url)
?.catch(() => {
this.downloadLocks.delete(url);
return url
})?.finally(() => {
this.downloadLocks.delete(url);
});
this.downloadLocks.set(url, downloadPromise);
}
}
// 获取图片(带并发控制)
async getImage(context: Context, url: string): Promise<string | image.PixelMap> {
let downloadPromise = this.downloadLocks.get(url);
if (!downloadPromise) {
downloadPromise = this.executeDownload(context, url)
?.catch(() => {
this.downloadLocks.delete(url);
return url
})
?.finally(() => {
this.downloadLocks.delete(url);
});
this.downloadLocks.set(url, downloadPromise);
}
return downloadPromise;
}
// 执行实际下载逻辑
private async executeDownload(context: Context, url: string): Promise<string | image.PixelMap> {
return fetchImagePixelMap(context, url); // 恢复通过线程池执行
}
}
使用实例
import { image } from '@kit.ImageKit';
import { ImageDownloader } from '../tool/ImageDownloader';
@Entry
@Component
struct Home {
@State imagePixelMap:image.PixelMap | string = ""
aboutToAppear(): void {
let downLoadUrl = this.url
if (downLoadUrl) {
ImageDownloader.getInstance().getImage(getContext(), downLoadUrl).then((imagePixelMap) => {
this.imagePixelMap = imagePixelMap
})
}
}
url = "https://ts1.tc.mm.bing.net/th/id/" +
"R-C.987f582c510be58755c4933cda68d525?rik=C0D21hJDYvXosw&" +
"riu=http%3a%2f%2fimg.pconline.com.cn%2fimages%2fupload%2fupc%2ftx%2fwall" +
"paper%2f1305%2f16%2fc4%2f20990657_1368686545122.jpg&" +
"ehk=netN2qzcCVS4ALUQfDOwxAwFcy41oxC%2b0xTFvOYy5ds%3d&risl=&pid=ImgRaw&r=0"
build() {
Column() {
Image(this.imagePixelMap)
}
.height('100%')
.width('100%')
}
}
这是基于系统组件Image使用,另一种封装方式是创建一个新的自定义组件,传入url等配置,组件内部在使用系统组件显示。 这种图片缓存工具常用的三方库可以参考 ImageKnife
更多推荐


所有评论(0)