diff --git a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets index 9281818..1dd5f1c 100644 --- a/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets +++ b/entry/src/main/ets/pages/imageknifeTestCaseIndex.ets @@ -354,6 +354,14 @@ struct IndexFunctionDemo { router.pushUrl({ url: 'pages/testImageKnifeHttpRequestHeader' }); }).margin({ top: 5, left: 3 }) }.width('100%').height(60).backgroundColor(Color.Pink) + + Text('测试图片缓存内存').fontSize(15) + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('测试图片缓存内存') + .onClick(() => { + router.pushUrl({ url: 'pages/testImageKnifeCache' }); + }).margin({ top: 5, left: 3 }) + }.width('100%').height(60).backgroundColor(Color.Pink) } } .width('100%') diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json index 12883ee..61208cf 100644 --- a/entry/src/main/resources/base/profile/main_pages.json +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -44,6 +44,8 @@ "pages/testImageKnifeAutoPage", "pages/testImageKnifeAutoWidthPage", "pages/testImageKnifeAutoHeightPage", - "pages/testReusePhotoPage" + "pages/testReusePhotoPage", + "pages/testImageKnifeCache" + ] } \ No newline at end of file diff --git a/library/src/main/ets/components/imageknife/ImageKnife.ets b/library/src/main/ets/components/imageknife/ImageKnife.ets index 57ec07b..f6f959b 100644 --- a/library/src/main/ets/components/imageknife/ImageKnife.ets +++ b/library/src/main/ets/components/imageknife/ImageKnife.ets @@ -16,7 +16,7 @@ import { DiskLruCache } from "../cache/DiskLruCache" import { EngineKeyFactories } from "../cache/key/EngineKeyFactories" import { EngineKeyInterface } from "../cache/key/EngineKeyInterface" -import { RequestOption, Size } from "../imageknife/RequestOption" +import { CacheType, RequestOption, Size } from "../imageknife/RequestOption" import { AsyncCallback } from "../imageknife/interface/AsyncCallback" import { PlaceHolderManager } from "../imageknife/holder/PlaceHolderManager" import { RetryHolderManager } from "../imageknife/holder/RetryHolderManager" @@ -48,6 +48,10 @@ import { MemoryCacheProxy } from './requestmanage/MemoryCacheProxy' import { ObjectKey } from './ObjectKey' import { TaskParams } from './TaskParams' import { Constants } from './constants/Constants' +import { GIFParseImpl } from './utils/gif/GIFParseImpl' +import { SVGParseImpl } from './utils/svg/SVGParseImpl' +import { ParseImageUtil } from './utils/ParseImageUtil' +import { IParseImage } from './interface/IParseImage' export class ImageKnife { static readonly SEPARATOR: string = '/' @@ -77,9 +81,10 @@ export class ImageKnife { defaultLifeCycle: IDrawLifeCycle | undefined = undefined; // 开发者可配置全局缓存 engineKeyImpl: EngineKeyInterface; + private mParseImageUtil: IParseImage; private constructor() { - + this.mParseImageUtil = new ParseImageUtil(); this.runningMaps = new EasyLinkedHashMap(); this.pendingMaps = new EasyLinkedHashMap(); this.pausedMaps = new EasyLinkedHashMap(); @@ -321,6 +326,91 @@ export class ImageKnife { return this.parseSource(request); } + + public isUrlExist(request: RequestOption): Promise { + + return new Promise((resolve, reject) => { + this.generateDataCacheKey(request); + let loadComplete = (imageKnifeData: ImageKnifeData) => { + resolve(imageKnifeData); + } + let loadError = (err ?: BusinessError | string) => { + reject(undefined); + } + this.loadMemoryCacheAndDiskFrom(request, loadComplete, loadError); + }) + } + + loadMemoryCacheAndDiskFrom(request: RequestOption, onComplete: (imageKnifeData: ImageKnifeData) => void | PromiseLike, onError: (err?: BusinessError | string) => void) { + + if (request.cacheType == CacheType.Cache) { + + let cache = this.memoryCacheProxy.loadMemoryCache(request.generateCacheKey, true); + if (cache == null || typeof cache == 'undefined') { + onError("No data in cache!") + }else { + cache.waitSaveDisk = false; + //2.网络缓存有数据,返回 + onComplete(cache); + } + + }else if (request.cacheType == CacheType.Disk){ + let cached: ArrayBuffer = DiskLruCache.getFileCacheByFile((ImageKnifeGlobal.getInstance() + .getHapContext() as common.UIAbilityContext).filesDir as string, request.generateDataKey) as ArrayBuffer; + + if (cached != null) { + + let filetype: string | null = this.fileTypeUtil.getFileType(cached); + + if (filetype == null) { + onError('请检查数据源'); + return; + } + + if (!this.fileTypeUtil.isImage(cached)) { + onError('暂不支持的类型!类型=' + filetype); + } + + if (ImageKnifeData.GIF == filetype && !request.dontAnimateFlag) { + let gifParseImpl = new GIFParseImpl() + gifParseImpl.parseGifs(cached, (data?: GIFFrame[], err?: BusinessError | string) => { + if (err) { + onError(err) + } + LogUtil.log("gifProcess data is null:" + (data == null)); + if (!!data) { + let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data); + LogUtil.log('gifProcess 生成gif 返回数据类型') + onComplete(imageKnifeData) + } else { + onError('Parse GIF callback data is null, you need check callback data!') + } + }) + + } else if (ImageKnifeData.SVG == filetype) { + let svgParseImpl = new SVGParseImpl() + let success = (value: PixelMap) => { + let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value); + onComplete(imageKnifeData); + } + svgParseImpl.parseSvg(request, cached, success, onError) + } else { + //5.磁盘有数据,解析错误返回onError + let success = (value: PixelMap) => { + let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value); + onComplete(imageKnifeData); + } + this.mParseImageUtil.parseImage(cached, success, onError) + } + + } else { + //6.磁盘无数据,返回onError + onError("No data in disk cache!") + } + } + } + + generateDataCacheKey(request: RequestOption) { let factories: EngineKeyInterface; let cacheKey: string; @@ -588,10 +678,10 @@ export class ImageKnife { retryholderSrc: request.retryholderSrc, }); //使用taskpool多线程执行资源下载 - let task:ESObject = new taskpool.Task(taskExecute, taskParams, loadSrcJson) + let task: ESObject = new taskpool.Task(taskExecute, taskParams, loadSrcJson) task.setTransferList([]) - emitter.on(Constants.PROGRESS_EMITTER as ESObject, (data:ESObject) => { + emitter.on(Constants.PROGRESS_EMITTER as ESObject, (data: ESObject) => { if (request.progressFunc && data?.data?.value) { let percent = data.data.value as number; request.progressFunc.asyncSuccess(percent); diff --git a/library/src/main/ets/components/imageknife/RequestOption.ets b/library/src/main/ets/components/imageknife/RequestOption.ets index a2b3c84..332b5d3 100644 --- a/library/src/main/ets/components/imageknife/RequestOption.ets +++ b/library/src/main/ets/components/imageknife/RequestOption.ets @@ -69,6 +69,14 @@ export interface DetachFromLayout { detach: () => void } +export enum CacheType { + //缓存 + Cache, + //磁盘 + Disk + +} + export class RequestOption { // 遍历添加图片http请求头 headers: Map = new Map(); @@ -83,6 +91,7 @@ export class RequestOption { this.headers = map; } + cacheType: CacheType = CacheType.Disk; uuid: string = '' // 唯一标识 loadSrc: string | PixelMap | Resource = ''; strategy: DiskStrategy = new AUTOMATIC(); @@ -186,6 +195,12 @@ export class RequestOption { return this; } + + setCacheType(cacheType: CacheType) { + this.cacheType = cacheType; + return this; + } + getFilesPath() { return this.filesPath; } @@ -466,10 +481,10 @@ export class RequestOption { } // 占位图解析成功 - placeholderOnComplete = (imageKnifeData:ImageKnifeData) => { + placeholderOnComplete = (imageKnifeData: ImageKnifeData) => { LogUtil.log("placeholderOnComplete has called!"); LogUtil.log("Main Image is Ready:" + this.loadMainReady); - this.setMemoryCache(imageKnifeData,this.placeholderCacheKey); + this.setMemoryCache(imageKnifeData, this.placeholderCacheKey); if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) { // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 if (this.placeholderSrc != undefined) { @@ -501,8 +516,8 @@ export class RequestOption { LogUtil.log("缩略图解析失败 error =" + error) } // 加载失败 占位图解析成功 - errorholderOnComplete = (imageKnifeData:ImageKnifeData) => { - this.setMemoryCache(imageKnifeData,this.errorholderCacheKey); + errorholderOnComplete = (imageKnifeData: ImageKnifeData) => { + this.setMemoryCache(imageKnifeData, this.errorholderCacheKey); // 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用 this.errorholderData = imageKnifeData; if (this.loadErrorReady) { @@ -515,8 +530,8 @@ export class RequestOption { errorholderOnError = (error: BusinessError | string) => { LogUtil.log("失败占位图解析失败 error =" + error) } - retryholderOnComplete = (imageKnifeData:ImageKnifeData) => { - this.setMemoryCache(imageKnifeData,this.retryholderCacheKey); + retryholderOnComplete = (imageKnifeData: ImageKnifeData) => { + this.setMemoryCache(imageKnifeData, this.retryholderCacheKey); this.retryholderData = imageKnifeData; if (this.loadRetryReady) { if (this.retryholderFunc != undefined) { @@ -528,7 +543,7 @@ export class RequestOption { LogUtil.log("重试占位图解析失败 error =" + error) } loadComplete = (imageKnifeData: ImageKnifeData) => { - this.setMemoryCache(imageKnifeData,this.generateCacheKey); + this.setMemoryCache(imageKnifeData, this.generateCacheKey); if (typeof this.loadSrc == 'string') { this.setDiskCache(); } @@ -584,7 +599,7 @@ export class RequestOption { } } //设置内存缓存 - setMemoryCache = (imageKnifeData: ImageKnifeData,cacheKey:string) => { + setMemoryCache = (imageKnifeData: ImageKnifeData, cacheKey: string) => { let memoryCacheProxy = ImageKnifeGlobal.getInstance() .getImageKnife()?.getMemoryCacheProxy() as MemoryCacheProxy;