diff --git a/entry/src/main/ets/pages/TestImageKnifeCallbackPage.ets b/entry/src/main/ets/pages/TestImageKnifeCallbackPage.ets index d7b66f3..f6dae0c 100644 --- a/entry/src/main/ets/pages/TestImageKnifeCallbackPage.ets +++ b/entry/src/main/ets/pages/TestImageKnifeCallbackPage.ets @@ -94,7 +94,6 @@ struct TestImageKnifeCallbackPage { }, border: { radius: 50 }, onComplete: (event) => { - console.log("sss--->gif onComplete:" + JSON.stringify(event)) if (event && event.loadingStatus == 0) { this.render_success = JSON.stringify(Date.now()) } diff --git a/library/oh-package-lock.json5 b/library/oh-package-lock.json5 deleted file mode 100644 index 3245bae..0000000 --- a/library/oh-package-lock.json5 +++ /dev/null @@ -1,6 +0,0 @@ -{ - "lockfileVersion": 3, - "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", - "specifiers": {}, - "packages": {} -} \ No newline at end of file diff --git a/library/src/main/ets/ImageKnifeDispatcher.ets b/library/src/main/ets/ImageKnifeDispatcher.ets index fbbb3a8..ebb1a43 100644 --- a/library/src/main/ets/ImageKnifeDispatcher.ets +++ b/library/src/main/ets/ImageKnifeDispatcher.ets @@ -19,10 +19,10 @@ import List from '@ohos.util.List'; import LightWeightMap from '@ohos.util.LightWeightMap'; import { LogUtil } from './utils/LogUtil'; import { ImageKnife } from './ImageKnife'; -import { ImageKnifeData, CacheStrategy } from './model/ImageKnifeData'; +import { ImageKnifeData, CacheStrategy, ErrorInfo, TimeInfo } from './model/ImageKnifeData'; import image from '@ohos.multimedia.image'; import emitter from '@ohos.events.emitter'; -import { Constants } from './utils/Constants'; +import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants'; import taskpool from '@ohos.taskpool'; import { FileTypeUtil } from './utils/FileTypeUtil'; import { IEngineKey } from './key/IEngineKey'; @@ -46,9 +46,19 @@ export class ImageKnifeDispatcher { executingJobMap: LightWeightMap> = new LightWeightMap(); // 开发者可配置全局缓存 private engineKey: IEngineKey = new DefaultEngineKey(); + //图片加载信息回调数据 + private callBackData: ImageKnifeData = { + source: "", + imageWidth: 0, + imageHeight: 0, + }; + private callBackTimeInfo: TimeInfo = {}; - showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean { - LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" + requestSource + " isAnimator=" + isAnimator) + showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, + requestSource: ImageKnifeRequestSource, isAnimator?: boolean): boolean { + LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" + + requestSource + " isAnimator=" + isAnimator) + let memoryCheckStartTime = Date.now(); let memoryCache: ImageKnifeData | undefined; if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') { memoryCache = { @@ -58,26 +68,39 @@ export class ImageKnifeDispatcher { } } else { memoryCache = ImageKnife.getInstance() - .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator)); + .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption, + isAnimator)); + } + //记录ImageKnifeRequestSource.SRC 开始内存检查的时间点 + if (requestSource == ImageKnifeRequestSource.SRC) { + this.callBackTimeInfo.memoryCheckStartTime = memoryCheckStartTime; + this.callBackTimeInfo.memoryCheckEndTime = Date.now(); + this.callBackData.timeInfo = this.callBackTimeInfo; + //设置请求结束的时间点 + if (memoryCache !== undefined) { + this.callBackData.timeInfo.requestEndTime = Date.now(); + } } - if (memoryCache !== undefined) { // 画主图 if (request.requestState === ImageKnifeRequestState.PROGRESS) { // 回调请求开始 - if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { - request.imageKnifeOption.onLoadListener.onLoadStart() + if (requestSource === ImageKnifeRequestSource.SRC && + request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { + request.imageKnifeOption.onLoadListener.onLoadStart(this.callBackData) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc) } LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc) - request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,memoryCache.imageAnimator) + request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource, + memoryCache.imageAnimator) LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc) if (requestSource == ImageKnifeRequestSource.SRC) { request.requestState = ImageKnifeRequestState.COMPLETE // 回调请求开结束 if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) { - request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source,memoryCache) + this.copyCallBackData(this.callBackData, memoryCache); + request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source, memoryCache) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc) } } else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) { @@ -91,15 +114,53 @@ export class ImageKnifeDispatcher { return false } + /** + * 设置进入线程前加载图片的callBack信息 + * @param beforeCallData + * @param afterCallData + */ + private copyCallBackData(beforeCallData: ImageKnifeData | undefined, afterCallData: ImageKnifeData) { + if (!beforeCallData || !afterCallData) { + return; + } + //设置组件宽高 + afterCallData.componentWidth = beforeCallData.componentWidth; + afterCallData.componentHeight = beforeCallData.componentWidth; + //设置图片开始加载时间及其缓存检查时间点 + if (beforeCallData.timeInfo) { + if (afterCallData.timeInfo) { + afterCallData.timeInfo.requestStartTime = beforeCallData.timeInfo.requestStartTime; + afterCallData.timeInfo.memoryCheckStartTime = beforeCallData.timeInfo.memoryCheckStartTime; + afterCallData.timeInfo.memoryCheckEndTime = beforeCallData.timeInfo.memoryCheckEndTime; + } else { + afterCallData.timeInfo = beforeCallData.timeInfo; + } + } + } - enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void { + + enqueue(request: ImageKnifeRequest, isAnimator?: boolean): void { + + if (typeof request.imageKnifeOption.loadSrc == "string") { + this.callBackData.source = request.imageKnifeOption.loadSrc; + } + this.callBackData.componentWidth = request.componentWidth; + this.callBackData.componentHeight = request.componentHeight; + this.callBackTimeInfo.requestStartTime = Date.now(); //1.内存有的话直接渲染 - if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) { + if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, isAnimator)) { return } + + //这里对this.callBackData要进行深拷贝 + let call = JSON.parse(JSON.stringify(this.callBackData)) as ImageKnifeData; + + //跟隨請求保存回調信息點 + request.setImageKnifeData(call); // 2.内存获取占位图 if (request.imageKnifeOption.placeholderSrc !== undefined) { - if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)) { + if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, + ImageKnifeRequestSource.PLACE_HOLDER)) { request.drawPlayHolderSuccess = true } } @@ -108,10 +169,10 @@ export class ImageKnifeDispatcher { this.jobQueue.add(request) return } - this.executeJob(request,isAnimator) + this.executeJob(request, isAnimator) } - executeJob(request: ImageKnifeRequest,isAnimator?: boolean): void { + executeJob(request: ImageKnifeRequest, isAnimator?: boolean): void { LogUtil.log("ImageKnife_DataTime_executeJob.start:" + request.imageKnifeOption.loadSrc) // 加载占位符 if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) { @@ -119,16 +180,18 @@ export class ImageKnifeDispatcher { } // 加载主图 - this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator) + this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, isAnimator) LogUtil.log("ImageKnife_DataTime_executeJob.end:" + request.imageKnifeOption.loadSrc) } /** * 获取和显示图片 */ - getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): void { + getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, + requestSource: ImageKnifeRequestSource, isAnimator?: boolean): void { LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc) - let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator) + let memoryKey: string = + this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption, isAnimator) let requestList: List | undefined = this.executingJobMap.get(memoryKey) if (requestList == undefined) { requestList = new List() @@ -139,28 +202,29 @@ export class ImageKnifeDispatcher { return } - let isWatchProgress : boolean = false - + let isWatchProgress: boolean = false // 回调请求开始 requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { - if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { - requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart() + if (requestWithSource.source === ImageKnifeRequestSource.SRC && + requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { + requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart(currentRequest.getImageKnifeData()) LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc) } - if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { + if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && + requestWithSource.source === ImageKnifeRequestSource.SRC) { isWatchProgress = true } }); let src: string | number = "" let moduleName: string = "" let resName: string = "" - if((imageSrc as Resource).id != undefined) { + if ((imageSrc as Resource).id != undefined) { moduleName = (imageSrc as Resource).moduleName src = (imageSrc as Resource).id - if(src == -1) { + if (src == -1) { resName = (imageSrc as Resource).params![0] } - } else if(typeof imageSrc == "string") { + } else if (typeof imageSrc == "string") { src = imageSrc } let request: RequestJobRequest = { @@ -168,61 +232,65 @@ export class ImageKnifeDispatcher { src: src, headers: currentRequest.imageKnifeOption.headerOption, allHeaders: currentRequest.headers, - componentWidth:currentRequest.componentWidth, - componentHeight:currentRequest.componentHeight, + componentWidth: currentRequest.componentWidth, + componentHeight: currentRequest.componentHeight, customGetImage: currentRequest.imageKnifeOption.customGetImage, onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache, transformation: currentRequest.imageKnifeOption.transformation, writeCacheStrategy: ImageKnife.getInstance() - .isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存 + .isFileCacheInit() ? currentRequest.imageKnifeOption.writeCacheStrategy : + CacheStrategy.Memory, // 未初始化文件缓存时,不写文件缓存 engineKey: this.engineKey, signature: currentRequest.imageKnifeOption.signature, requestSource: requestSource, isWatchProgress: isWatchProgress, memoryKey: memoryKey, fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(), - isAnimator:isAnimator, + isAnimator: isAnimator, moduleName: moduleName == "" ? undefined : moduleName, resName: resName == "" ? undefined : resName } - if(request.customGetImage == undefined) { + if (request.customGetImage == undefined) { request.customGetImage = ImageKnife.getInstance().getCustomGetImage() } - if (ImageKnife.getInstance().isRequestInSubThread){ + if (ImageKnife.getInstance().isRequestInSubThread) { // 启动线程下载和解码主图 LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc) let task = new taskpool.Task(requestJob, request) LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.end:" + currentRequest.imageKnifeOption.loadSrc) - if (isWatchProgress){ + if (isWatchProgress) { emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => { - this.progressCallBack(requestList! , data?.data?.value as number) + this.progressCallBack(requestList!, data?.data?.value as number) }); } - LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + + currentRequest.imageKnifeOption.loadSrc) taskpool.execute(task).then((res: Object) => { - this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); - if (isWatchProgress){ + this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, + requestSource, isAnimator); + if (isWatchProgress) { emitter.off(Constants.PROGRESS_EMITTER + memoryKey) } - LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) - LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:" + currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) }).catch((err: BusinessError) => { LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) - if (isWatchProgress){ + if (isWatchProgress) { emitter.off(Constants.PROGRESS_EMITTER + memoryKey) } this.executingJobMap.remove(memoryKey); this.dispatchNextJob(); }) } else { //主线程请求 - LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + + currentRequest.imageKnifeOption.loadSrc) requestJob(request, requestList).then((res: RequestJobResult | undefined) => { - this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) - LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) + this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator); + LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:" + currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) }).catch((err: BusinessError) => { LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err) LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) @@ -237,31 +305,52 @@ export class ImageKnifeDispatcher { * @param requestList 请求列表 * @param data 进度 */ - private progressCallBack(requestList:List, data: number) { + private progressCallBack(requestList: List, data: number) { for (let i = 0; i < requestList.length; i++) { - let requestWithSource:ImageKnifeRequestWithSource = requestList[i] - if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { + let requestWithSource: ImageKnifeRequestWithSource = requestList[i] + if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && + requestWithSource.source === ImageKnifeRequestSource.SRC) { requestWithSource.request.imageKnifeOption.progressListener(data) } } } - private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List , - currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void { - LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:"+currentRequest.imageKnifeOption.loadSrc) - if (requestJobResult === undefined){ + private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List, + currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, + requestSource: ImageKnifeRequestSource, isAnimator?: boolean): void { + LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:" + currentRequest.imageKnifeOption.loadSrc) + if (requestJobResult === undefined) { return } + //设置请求结束的时间 + if (requestJobResult.callBackData && requestJobResult.callBackData.timeInfo) { + requestJobResult.callBackData.timeInfo.requestEndTime = Date.now(); + } + let pixelmap = requestJobResult.pixelMap; if (pixelmap === undefined) { - LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:" + + currentRequest.imageKnifeOption.loadSrc) requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { + + //设置失败回调的时间点 + if (requestJobResult.errorCallBackData && requestJobResult.errorCallBackData.timeInfo) { + requestJobResult.errorCallBackData.timeInfo.requestEndTime = Date.now() + let callBackData = requestWithSource.request.getImageKnifeData(); + if (callBackData && callBackData.timeInfo) { + requestJobResult.errorCallBackData.timeInfo.requestStartTime = callBackData.timeInfo.requestStartTime; + requestJobResult.errorCallBackData.timeInfo.memoryCheckStartTime = + callBackData.timeInfo.memoryCheckStartTime; + requestJobResult.errorCallBackData.timeInfo.memoryCheckEndTime = callBackData.timeInfo.memoryCheckEndTime; + } + } // 回调请求失败 if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined && requestJobResult.loadFail) { - requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc) + requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail, + requestJobResult.errorCallBackData); + LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:" + currentRequest.imageKnifeOption.loadSrc) } if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) { @@ -278,36 +367,57 @@ export class ImageKnifeDispatcher { return; } // 保存文件缓存 - if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) { - LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:"+currentRequest.imageKnifeOption.loadSrc) + if (requestJobResult.bufferSize > 0 && + currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) { + LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:" + + currentRequest.imageKnifeOption.loadSrc) ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:" + + currentRequest.imageKnifeOption.loadSrc) + } + let imageKnifeData: ImageKnifeData; + if (!requestJobResult.callBackData) { + imageKnifeData = { + source: pixelmap!, + imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width, + imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height, + type: requestJobResult.type, + }; + } else { + imageKnifeData = requestJobResult.callBackData; + imageKnifeData.source = pixelmap!; } - let ImageKnifeData: ImageKnifeData = { + if (requestJobResult.pixelMapList != undefined) { + let imageAnimator: Array = [] + requestJobResult.pixelMapList.forEach((item, index) => { + imageAnimator.push({ + src: requestJobResult.pixelMapList![index], + duration: requestJobResult.delayList![index] + }) + }) + imageKnifeData.imageAnimator = imageAnimator + } + //构建缓存保存的ImageKnifeData + let saveCacheImageData: ImageKnifeData = { source: pixelmap!, imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width, imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height, - type:requestJobResult.type - }; - if(requestJobResult.pixelMapList != undefined) { - let imageAnimator: Array = [] - requestJobResult.pixelMapList.forEach((item,index)=>{ - imageAnimator.push({ - src:requestJobResult.pixelMapList![index], - duration:requestJobResult.delayList![index] - }) - }) - ImageKnifeData.imageAnimator = imageAnimator + type: requestJobResult.type, + imageAnimator: imageKnifeData.imageAnimator } // 保存内存缓存 if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) { - LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:" + + currentRequest.imageKnifeOption.loadSrc) ImageKnife.getInstance() - .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator), - ImageKnifeData); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc) + .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption, + isAnimator), + saveCacheImageData); + LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:" + currentRequest.imageKnifeOption.loadSrc) } + + if (requestList !== undefined) { // key相同的request,一起绘制 requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { @@ -317,10 +427,12 @@ export class ImageKnifeDispatcher { requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER || (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER && requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) { - LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:" + + currentRequest.imageKnifeOption.loadSrc) requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion, - ImageKnifeData.source, requestWithSource.source,ImageKnifeData.imageAnimator); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc) + imageKnifeData.source, requestWithSource.source, imageKnifeData.imageAnimator); + LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:" + + currentRequest.imageKnifeOption.loadSrc) } if (requestWithSource.source == ImageKnifeRequestSource.SRC) { @@ -328,16 +440,38 @@ export class ImageKnifeDispatcher { if (requestWithSource.request.imageKnifeOption.onLoadListener && requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) { // 回调请求成功 - requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(ImageKnifeData.source,ImageKnifeData); - LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc) + this.copyCallBackData(requestWithSource.request.getImageKnifeData(), imageKnifeData); + requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(imageKnifeData.source, + imageKnifeData); + LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:" + + currentRequest.imageKnifeOption.loadSrc) } } else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) { requestWithSource.request.requestState = ImageKnifeRequestState.ERROR; } } else { - if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) { - // 回调请求成功 - requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") + if (requestWithSource.source == ImageKnifeRequestSource.SRC && + requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) { + // 回调请求取消 + //设置失败回调的时间点 + let callBackData = requestWithSource.request.getImageKnifeData(); + + if (requestJobResult.errorCallBackData && requestJobResult.errorCallBackData.timeInfo) { + requestJobResult.errorCallBackData.timeInfo.requestCancelTime = Date.now(); + requestJobResult.errorCallBackData.timeInfo.requestEndTime = Date.now() + requestJobResult.errorCallBackData.phase = LoadPhase.PHASE_WILL_SHOW; + requestJobResult.errorCallBackData.code = LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE; + if (callBackData && callBackData.timeInfo) { + requestJobResult.errorCallBackData.timeInfo.requestStartTime = + callBackData.timeInfo.requestStartTime; + requestJobResult.errorCallBackData.timeInfo.memoryCheckStartTime = + callBackData.timeInfo.memoryCheckStartTime; + requestJobResult.errorCallBackData.timeInfo.memoryCheckEndTime = + callBackData.timeInfo.memoryCheckEndTime; + } + } + requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed", + requestJobResult.errorCallBackData) } } }); @@ -347,7 +481,7 @@ export class ImageKnifeDispatcher { } else { LogUtil.log("error: no requestlist need to draw for key = " + memoryKey); } - LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:"+currentRequest.imageKnifeOption.loadSrc) + LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:" + currentRequest.imageKnifeOption.loadSrc) } @@ -358,14 +492,32 @@ export class ImageKnifeDispatcher { if (request === undefined) { LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:no any job") break // 队列已无任务 - } - else if (request.requestState === ImageKnifeRequestState.PROGRESS) { + } else if (request.requestState === ImageKnifeRequestState.PROGRESS) { LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start executeJob:" + request.imageKnifeOption.loadSrc) this.executeJob(request) LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc) break - }else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) { - request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") + } else if (request.requestState == ImageKnifeRequestState.DESTROY && + request.imageKnifeOption.onLoadListener?.onLoadCancel) { + + //构建回调错误信息 + let callBackData = request.getImageKnifeData(); + let timeInfo: TimeInfo = {}; + timeInfo.requestCancelTime = Date.now(); + timeInfo.requestEndTime = Date.now() + timeInfo.requestCancelTime = Date.now(); + if (callBackData && callBackData.timeInfo) { + timeInfo.requestStartTime = callBackData.timeInfo.requestStartTime; + timeInfo.memoryCheckStartTime = callBackData.timeInfo.memoryCheckStartTime; + timeInfo.memoryCheckEndTime = callBackData.timeInfo.memoryCheckEndTime; + } + let errorInfo: ErrorInfo = { + phase: LoadPhase.PHASE_THREAD_QUEUE, + code: LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE, + timeInfo:timeInfo + }; + + request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed", errorInfo) } } } @@ -392,43 +544,56 @@ export class ImageKnifeDispatcher { * @returns */ @Concurrent -async function requestJob(request: RequestJobRequest, requestList?: List): Promise { +async function requestJob(request: RequestJobRequest, + requestList?: List): Promise { LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource) - let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src + let src = + typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src // 生成文件缓存key let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator) + //定义加载信息回调数据 + let callBackData: ImageKnifeData = { source: "", imageWidth: 0, imageHeight: 0 }; + //定义图片各个阶段错误信息 + let errorCallBackData: ErrorInfo = { code: 0, phase: LoadPhase.PHASE_LOAD } + //获取图片资源 let resBuf: ArrayBuffer try { LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src) - resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey) + resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey, callBackData, errorCallBackData) LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src) } catch (error) { LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error) - return ImageKnifeLoader.makeEmptyResult(error) + return ImageKnifeLoader.makeEmptyResult(error, errorCallBackData) } // 获取图片类型 let typeValue = new FileTypeUtil().getFileType(resBuf); - if(typeValue == null) { + if (typeValue == null) { LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src) - return ImageKnifeLoader.makeEmptyResult("request is not a valid image source") + return ImageKnifeLoader.makeEmptyResult("request is not a valid image source", errorCallBackData) } - // 解析图片 + LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src) - let result: RequestJobResult = await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request) + let result: RequestJobResult = + await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData) LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src) // 图形变化 - if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') { + if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && + result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') { LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src) - result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, request.componentHeight); + result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, + request.componentHeight); LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src) } LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src) + + result.callBackData = callBackData; + result.errorCallBackData = errorCallBackData; return result } diff --git a/library/src/main/ets/ImageKnifeLoader.ets b/library/src/main/ets/ImageKnifeLoader.ets index 1c14d0c..a73bba9 100644 --- a/library/src/main/ets/ImageKnifeLoader.ets +++ b/library/src/main/ets/ImageKnifeLoader.ets @@ -14,8 +14,14 @@ */ import { CacheStrategy, + DecodeImageInfo, + ErrorInfo, + ImageKnifeData, ImageKnifeRequestSource, - ImageKnifeRequestWithSource, RequestJobRequest } from './model/ImageKnifeData'; + ImageKnifeRequestWithSource, + RequestJobRequest, + TimeInfo +} from './model/ImageKnifeData'; import List from '@ohos.util.List' import { FileCache } from './cache/FileCache'; import { LogUtil } from './utils/LogUtil'; @@ -28,6 +34,7 @@ import emitter from '@ohos.events.emitter'; import image from '@ohos.multimedia.image'; import { RequestJobResult } from './model/ImageKnifeData' import util from '@ohos.util'; +import { LoadPixelMapCode, LoadPhase } from './utils/Constants'; class RequestData { receiveSize: number = 2000 @@ -39,62 +46,104 @@ class RequestData { */ export class ImageKnifeLoader { static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, - request: RequestJobRequest): Promise { - if(request.isAnimator) { - return ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request) + request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise { + if (request.isAnimator) { + return ImageKnifeLoader.parseForAnimatorComponent(resBuf, typeValue, fileKey, request, callBackData, + errorCallBackData) } if (typeValue === 'gif' || typeValue === 'webp') { - return ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request) - } else if(typeValue == "svg") { - return ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request) + return ImageKnifeLoader.parseAnimatorImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData) + } else if (typeValue == "svg") { + return ImageKnifeLoader.parseSvgImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData) } - return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) + return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData) } - static makeEmptyResult(error: string): RequestJobResult{ + static makeEmptyResult(error: string, errorInfo?: ErrorInfo): RequestJobResult { return { pixelMap: undefined, bufferSize: 0, fileKey: '', loadFail: error, + errorCallBackData: errorInfo } } - static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest):Promise { + static throwError(error: string, errorInfo: ErrorInfo, code: number, timeInfo: TimeInfo) { + errorInfo.code = code + errorInfo.timeInfo = timeInfo; + throw new Error(error); + } + + static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, + request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise { let resPixelmap: PixelMap | undefined = undefined + let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {} let decodingOptions: image.DecodingOptions = { - editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, + editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : + false, } let imageSource: image.ImageSource = image.createImageSource(resBuf) - if (imageSource === undefined){ + if (imageSource === undefined) { + errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE; + errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE; return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") } let size = (await imageSource.getImageInfo()).size + + callBackData.type = typeValue; + callBackData.imageWidth = size.width; + callBackData.imageHeight = size.height; + callBackData.imageSize = resBuf.byteLength; + callBackData.timeInfo = timeInfo; + timeInfo.decodeStartTime = Date.now(); await imageSource.createPixelMap(decodingOptions) .then((pixelmap: PixelMap) => { resPixelmap = pixelmap + timeInfo.decodeEndTime = Date.now(); imageSource.release() }).catch((error: BusinessError) => { imageSource.release() + timeInfo.decodeEndTime = Date.now(); + errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP; + errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE; + errorCallBackData.timeInfo = timeInfo; return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) }) + //获取各个pixelMap的大小 + if (resPixelmap && typeof resPixelmap !== "string") { + let decodeImages: Array = []; + let size = (resPixelmap as PixelMap).getImageInfoSync().size; + let decodeImage: DecodeImageInfo = { + contentWidth: size.width, + contentHeight: size.height, + contentSize: (resPixelmap as PixelMap).getPixelBytesNumber() + } + decodeImages.push(decodeImage); + callBackData.decodeImages = decodeImages; + } + return { pixelMap: resPixelmap, bufferSize: resBuf.byteLength, fileKey: fileKey, - size:size, - type:typeValue + size: size, + type: typeValue }; } + static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, - request: RequestJobRequest): Promise { - let resPixelmap: PixelMap | undefined = undefined + request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise { + let resPixelMap: PixelMap | undefined = undefined + let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {} let imageSource: image.ImageSource = image.createImageSource(resBuf) - if (imageSource === undefined){ + if (imageSource === undefined) { + errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE; + errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE; return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") } @@ -110,59 +159,106 @@ export class ImageKnifeLoader { editable: true, desiredSize: defaultSize }; + callBackData.type = typeValue; + callBackData.imageWidth = size.width; + callBackData.imageHeight = size.height; + callBackData.imageSize = resBuf.byteLength; + callBackData.timeInfo = timeInfo; + timeInfo.decodeStartTime = Date.now(); + await imageSource.createPixelMap(opts) - .then((pixelmap: PixelMap) => { - resPixelmap = pixelmap + .then((pixelMap: PixelMap) => { + resPixelMap = pixelMap imageSource.release() }).catch((error: BusinessError) => { imageSource.release() + timeInfo.decodeEndTime = Date.now(); + errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP; + errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE; + errorCallBackData.timeInfo = timeInfo; return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) }) + //获取各个pixelMap的大小 + if (resPixelMap && typeof resPixelMap !== "string") { + let decodeImages: Array = []; + let decodeImage: DecodeImageInfo = { + contentWidth: defaultSize.width, + contentHeight: defaultSize.height, + contentSize: (resPixelMap as PixelMap).getPixelBytesNumber() + } + decodeImages.push(decodeImage); + } + return { - pixelMap: resPixelmap, + pixelMap: resPixelMap, bufferSize: resBuf.byteLength, fileKey: fileKey, - type:typeValue + type: typeValue }; } + static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string, - fileKey: string,request: RequestJobRequest): Promise { + fileKey: string, request: RequestJobRequest, callBackData: ImageKnifeData, + errorCallBackData: ErrorInfo): Promise { let imageSource: image.ImageSource = image.createImageSource(resBuf) - if (imageSource === undefined){ + if (imageSource === undefined) { + errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE; + errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE; return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") } let frameCount = await imageSource.getFrameCount() let size = (await imageSource.getImageInfo()).size + callBackData.type = typeValue; + callBackData.frameCount = frameCount; + callBackData.imageWidth = size.width; + callBackData.imageHeight = size.height; + callBackData.imageSize = resBuf.byteLength; imageSource.release() - if(frameCount == undefined || frameCount == 1) { + if (frameCount == undefined || frameCount == 1) { } else { - let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf)) + let base64str = + "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf)) return { pixelMap: base64str, bufferSize: resBuf.byteLength, fileKey: fileKey, - size:size, - type:typeValue + size: size, + type: typeValue }; } - return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) + return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData, errorCallBackData) } + // 为AnimatorComponent解析动图 - static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest): Promise { + static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string, + request: RequestJobRequest, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise { + let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {} + + callBackData.type = typeValue; if (typeValue === 'gif' || typeValue === 'webp') { let imageSource: image.ImageSource = image.createImageSource(resBuf); - if (imageSource === undefined){ + if (imageSource === undefined) { + errorCallBackData.phase = LoadPhase.PHASE_CREATE_SOURCE; + errorCallBackData.code = LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE; return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") } let decodingOptions: image.DecodingOptions = { - editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, + editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : + false, } + callBackData.imageWidth = imageSource.getImageInfoSync().size.width; + callBackData.imageHeight = imageSource.getImageInfoSync().size.height; + callBackData.imageSize = resBuf.byteLength; + let pixelMapList: Array = [] let delayList: Array = [] + timeInfo.decodeStartTime = Date.now(); + let decodeImages: Array = []; await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array) => { + timeInfo.decodeEndTime = Date.now(); //sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList() await imageSource.getDelayTimeList().then(delayTimes => { if (pixelList.length > 0) { @@ -173,14 +269,29 @@ export class ImageKnifeLoader { } else { delayList.push(delayTimes[delayTimes.length - 1]) } + //获取各个pixelMap的大小 + let size = pixelList[i].getImageInfoSync().size + let decodeImage: DecodeImageInfo = { + contentWidth: size.width, + contentHeight: size.height, + contentSize: pixelList[i].getPixelBytesNumber() + } + decodeImages.push(decodeImage); } imageSource.release(); } }) }).catch((error: BusinessError) => { + timeInfo.decodeEndTime = Date.now(); imageSource.release() + errorCallBackData.phase = LoadPhase.PHASE_CREATE_PIXEL_MAP; + errorCallBackData.code = LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE; + errorCallBackData.timeInfo = timeInfo; return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) }) + callBackData.timeInfo = timeInfo; + callBackData.decodeImages = decodeImages; + errorCallBackData.timeInfo = timeInfo; return { pixelMap: "", bufferSize: resBuf.byteLength, @@ -190,47 +301,59 @@ export class ImageKnifeLoader { delayList } } else { + callBackData.timeInfo = timeInfo; + errorCallBackData.phase = LoadPhase.PHASE_PARSE_IAMGE; + errorCallBackData.timeInfo = timeInfo; + errorCallBackData.code = LoadPixelMapCode.IMAGE_FORMAT_ERROR_CODE return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图") } } // 获取图片资源 - static async getImageArrayBuffer(request: RequestJobRequest, requestList: List | undefined,fileKey:string): Promise { + static async getImageArrayBuffer(request: RequestJobRequest, + requestList: List | undefined, + fileKey: string, callBackData: ImageKnifeData, errorCallBackData: ErrorInfo): Promise { let resBuf: ArrayBuffer | undefined - + let timeInfo: TimeInfo = callBackData.timeInfo ? callBackData.timeInfo : {}; // 判断自定义下载 - if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") { + if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && + typeof request.src == "string") { // 先从文件缓存获取 - resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) + timeInfo.diskCheckStartTime = Date.now(); + resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder) + timeInfo.diskCheckEndTime = Date.now(); if (resBuf === undefined) { LogUtil.log("start customGetImage src=" + request.src) try { resBuf = await request.customGetImage(request.context, request.src) LogUtil.log("end customGetImage src=" + request.src) } catch (err) { - throw new Error('customGetImage loadFile failed! err = ' + err) + ImageKnifeLoader.throwError('customGetImage loadFile failed! err = ' + err, + errorCallBackData, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE, timeInfo) } if (resBuf === undefined) { - throw new Error('customGetImage loadFile failed!') + ImageKnifeLoader.throwError('customGetImage loadFile failed!', + errorCallBackData, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE, timeInfo) } // 保存文件缓存 - if (request.writeCacheStrategy !== CacheStrategy.Memory) { + if (resBuf && request.writeCacheStrategy !== CacheStrategy.Memory) { LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src) FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder) LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src) } } - } - else { + } else { if (typeof request.src === 'string') { if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载 // 先从文件缓存获取 - resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) - if (resBuf !== undefined){ + timeInfo.diskCheckStartTime = Date.now() + resBuf = FileCache.getFileCacheByFile(request.context, fileKey, request.fileCacheFolder) + timeInfo.diskCheckEndTime = Date.now() + if (resBuf !== undefined) { LogUtil.log("success get image from filecache for key = " + fileKey + " src = " + request.src) - } - else if (request.onlyRetrieveFromCache != true) { + } else if (request.onlyRetrieveFromCache != true) { LogUtil.log("HttpDownloadClient.start:" + request.src) + timeInfo.netRequestStartTime = Date.now(); let httpRequest = http.createHttp(); let progress: number = 0 let arrayBuffers = new Array() @@ -246,6 +369,11 @@ export class ImageKnifeLoader { } httpRequest.on("dataReceive", (data: ArrayBuffer) => { arrayBuffers.push(data) + //获取http下载的字节数 + if (callBackData.bufSize == undefined) { + callBackData.bufSize = 0; + } + callBackData.bufSize += data.byteLength; }); if (request.isWatchProgress) { @@ -258,10 +386,11 @@ export class ImageKnifeLoader { if (requestList === undefined) { // 子线程 emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } }) - }else { + } else { // 主线程请求 requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => { - if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { + if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && + requestWithSource.source === ImageKnifeRequestSource.SRC) { requestWithSource.request.imageKnifeOption.progressListener(progress) } }) @@ -281,42 +410,59 @@ export class ImageKnifeLoader { }); await promise.then((data: number) => { + errorCallBackData.phase = LoadPhase.PHASE_NET + errorCallBackData.httpCode = data; + timeInfo.netRequestEndTime = Date.now(); if (data == 200 || data == 206 || data == 204) { resBuf = combineArrayBuffers(arrayBuffers) } else { - throw new Error("HttpDownloadClient has error, http code =" + JSON.stringify(data)) + ImageKnifeLoader.throwError("HttpDownloadClient has error, http code =" + JSON.stringify(data), + errorCallBackData, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, timeInfo) } }).catch((err: Error) => { - throw new Error("HttpDownloadClient download ERROR : err = " + JSON.stringify(err)) + timeInfo.netRequestEndTime = Date.now(); + ImageKnifeLoader.throwError("HttpDownloadClient download ERROR : err = " + JSON.stringify(err), + errorCallBackData, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, timeInfo) }); LogUtil.log("HttpDownloadClient.end:" + request.src) // 保存文件缓存 if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) { - LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src) - FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder) - LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src) + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src) + FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder) + LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src) } - } - else { - throw new Error('onlyRetrieveFromCache,do not fetch image src = ' + request.src) + } else { + ImageKnifeLoader.throwError('onlyRetrieveFromCache,do not fetch image src = ' + request.src, + errorCallBackData, LoadPixelMapCode.IMAGE_RETRIEVE_CACHE_CODE, timeInfo) } } else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) { + errorCallBackData.phase = LoadPhase.PHASE_SHARE_FILE await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => { - await fs.stat(file.fd).then(async (stat) =>{ + await fs.stat(file.fd).then(async (stat) => { let buf = new ArrayBuffer(stat.size); await fs.read(file.fd, buf).then((readLen) => { resBuf = buf; fs.closeSync(file.fd); - }).catch((err:BusinessError) => { - throw new Error('LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }).catch((err: BusinessError) => { + ImageKnifeLoader.throwError('LoadDataShareFileClient fs.read err happened uri=' + request.src + + " err.msg=" + + err?.message + " err.code=" + err?.code, + errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo) }) - }).catch((err:BusinessError) => { - throw new Error('LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }).catch((err: BusinessError) => { + ImageKnifeLoader.throwError('LoadDataShareFileClient fs.stat err happened uri=' + request.src + + " err.msg=" + + err?.message + " err.code=" + err?.code, + errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo) }) - }).catch((err:BusinessError) => { - throw new Error('LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code) + }).catch((err: BusinessError) => { + ImageKnifeLoader.throwError('LoadDataShareFileClient fs.open err happened uri=' + request.src + + " err.msg=" + + err?.message + " err.code=" + err?.code, + errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE, timeInfo) }) } else { //从本地文件获取 + errorCallBackData.phase = LoadPhase.PHASE_LOCAL_FILE try { let stat = fs.statSync(request.src); if (stat.size > 0) { @@ -326,20 +472,22 @@ export class ImageKnifeLoader { fs.closeSync(file); } } catch (err) { - throw new Error(err) + ImageKnifeLoader.throwError(err, + errorCallBackData, LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE, timeInfo) } } } else if (typeof request.src == "number") { //从资源文件获取 let manager = request.context.createModuleContext(request.moduleName).resourceManager - if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) { - if(request.src == -1) { + if (resBuf == undefined && request.onlyRetrieveFromCache != true && + request.requestSource == ImageKnifeRequestSource.SRC) { + if (request.src == -1) { let resName = request.resName as string resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer } else { resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer } } else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) { - if(request.src == -1) { + if (request.src == -1) { let resName = request.resName as string resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer } else { @@ -349,9 +497,13 @@ export class ImageKnifeLoader { } } - if (resBuf === undefined){ + if (resBuf === undefined) { + errorCallBackData.code = LoadPixelMapCode.IMAGE_LOAD_FAILED_CODE + errorCallBackData.timeInfo = timeInfo; throw new Error('getImageArrayBuffer undefined') } + callBackData.timeInfo = timeInfo; + errorCallBackData.timeInfo = timeInfo; return resBuf } } \ No newline at end of file diff --git a/library/src/main/ets/components/ImageKnifeComponent.ets b/library/src/main/ets/components/ImageKnifeComponent.ets index f96cecc..b965dd5 100644 --- a/library/src/main/ets/components/ImageKnifeComponent.ets +++ b/library/src/main/ets/components/ImageKnifeComponent.ets @@ -53,23 +53,28 @@ export struct ImageKnifeComponent { aboutToAppear(): void { this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit - if(this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题,建议使用同步方式在aboutToAppear时加载图片 + if (this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题,建议使用同步方式在aboutToAppear时加载图片 let engineKey: IEngineKey = new DefaultEngineKey(); let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance() - .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) - if (memoryCacheSrc !== undefined){ - LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) + .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, + this.imageKnifeOption)) + if (memoryCacheSrc !== undefined) { + LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = " + + this.imageKnifeOption.loadSrc) this.pixelMap = memoryCacheSrc.source; - }else{ - LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) - if (this.imageKnifeOption.placeholderSrc !== undefined){ + } else { + LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = " + this.imageKnifeOption.loadSrc) + if (this.imageKnifeOption.placeholderSrc !== undefined) { let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance() - .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption)) - if (memoryCachePlace !== undefined){ - LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) + .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!, + ImageKnifeRequestSource.PLACE_HOLDER, this.imageKnifeOption)) + if (memoryCachePlace !== undefined) { + LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " + + this.imageKnifeOption.placeholderSrc) this.pixelMap = memoryCachePlace.source; - }else{ - LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) + } else { + LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + + this.imageKnifeOption.placeholderSrc) } } } @@ -87,7 +92,7 @@ export struct ImageKnifeComponent { /** * 对已DESTROY的组件不再发起请求 */ - private clearLastRequest(){ + private clearLastRequest() { if (this.request !== undefined) { this.request.requestState = ImageKnifeRequestState.DESTROY this.request = undefined @@ -104,7 +109,7 @@ export struct ImageKnifeComponent { .syncLoad(this.syncLoad) .draggable(false) .onComplete(this.imageKnifeOption.onComplete) - .onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => { + .onSizeChange((oldValue: SizeOptions, newValue: SizeOptions) => { this.currentWidth = newValue.width as number this.currentHeight = newValue.height as number this.lastWidth = oldValue.width as number @@ -138,7 +143,8 @@ export struct ImageKnifeComponent { height, this.componentVersion, { - showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => { + showPixelMap: async (version: number, pixelMap: PixelMap | string, + requestSource: ImageKnifeRequestSource) => { if (version !== this.componentVersion) { return //针对reuse场景,不显示历史图片 } @@ -154,10 +160,14 @@ export struct ImageKnifeComponent { this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit } else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) { this.objectFit = - this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit + this.imageKnifeOption.placeholderObjectFit === undefined ? + (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : + this.imageKnifeOption.placeholderObjectFit } else { this.objectFit = - this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit + this.imageKnifeOption.errorholderObjectFit === undefined ? + (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : + this.imageKnifeOption.errorholderObjectFit } } }) diff --git a/library/src/main/ets/model/ImageKnifeData.ets b/library/src/main/ets/model/ImageKnifeData.ets index e8a4c2a..3b2731f 100644 --- a/library/src/main/ets/model/ImageKnifeData.ets +++ b/library/src/main/ets/model/ImageKnifeData.ets @@ -20,12 +20,56 @@ import common from '@ohos.app.ability.common'; import { Size } from '@kit.ArkUI' export interface ImageKnifeData { - source: PixelMap | string, - imageWidth: number, + source: PixelMap | string, // url + imageWidth: number, // 原始宽高大小 imageHeight: number, - type?:string, - imageAnimator?: Array + imageSize?: number, + type?: string, + imageAnimator?: Array, + bufSize?: number, // 网络请求字节数 + componentWidth?: number //组件宽高 + componentHeight?: number + frameCount ?: number // 帧 + decodeImages?: Array //Image组件或者ImageAnimator组件可以加载一张或者多张 + timeInfo?: TimeInfo // 加载图片的各个时间点 } + +/** + * 解码后的图片的size + */ +export interface DecodeImageInfo { + contentWidth ?: number // 解码后宽高 + contentHeight?: number + contentSize ?: number // 大小 +} + +/** + * 加载的错误信息 + */ +export interface ErrorInfo { + phase: string, //图片加载阶段信息,如:网络加载阶段,缓存获取阶段及其解码阶段等 + code: number, + timeInfo?: TimeInfo, + httpCode?: number +} + +/** + * lru检查时间点 + */ +export interface TimeInfo { + requestStartTime?: number, + requestEndTime?: number, + requestCancelTime?: number, + memoryCheckStartTime?: number, + memoryCheckEndTime?: number, + diskCheckStartTime?: number, + diskCheckEndTime?: number, + netRequestStartTime?: number, + netRequestEndTime?: number, + decodeStartTime?: number, + decodeEndTime?: number, +} + /** * onComplete成功回调 */ @@ -40,6 +84,7 @@ export interface EventImage { contentOffsetX: number; contentOffsetY: number; } + /** * 缓存策略 */ @@ -75,10 +120,12 @@ export interface RequestJobResult { bufferSize: number fileKey: string loadFail?: string, - size?:Size, + size?: Size, type?: string, - pixelMapList?:Array, - delayList?: Array + pixelMapList?: Array, + delayList?: Array, + callBackData?: ImageKnifeData, + errorCallBackData?: ErrorInfo } /** @@ -102,7 +149,7 @@ export interface RequestJobRequest { memoryKey: string fileCacheFolder: string, isAnimator?: boolean, - moduleName?:string, + moduleName?: string, resName?: string } diff --git a/library/src/main/ets/model/ImageKnifeOption.ets b/library/src/main/ets/model/ImageKnifeOption.ets index 5c5f292..038e936 100644 --- a/library/src/main/ets/model/ImageKnifeOption.ets +++ b/library/src/main/ets/model/ImageKnifeOption.ets @@ -14,7 +14,7 @@ */ import taskpool from '@ohos.taskpool'; import common from '@ohos.app.ability.common' -import { CacheStrategy, ImageKnifeData,EventImage } from './ImageKnifeData'; +import { CacheStrategy, ImageKnifeData, EventImage, ErrorInfo } from './ImageKnifeData'; import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { drawing } from '@kit.ArkGraphics2D'; @@ -22,16 +22,18 @@ export interface HeaderOptions { key: string; value: Object; } + interface AnimatorType { state?: AnimationStatus iterations?: number reverse?: boolean - onStart?:()=>void - onFinish?:()=>void - onPause?:()=>void - onCancel?:()=>void - onRepeat?:()=>void + onStart?: () => void + onFinish?: () => void + onPause?: () => void + onCancel?: () => void + onRepeat?: () => void } + @ObservedV2 export class AnimatorOption { @Trace @@ -41,16 +43,17 @@ export class AnimatorOption { @Trace reverse?: boolean = false @Trace - onStart?:()=>void + onStart?: () => void @Trace - onFinish?:()=>void + onFinish?: () => void @Trace - onPause?:()=>void + onPause?: () => void @Trace - onCancel?:()=>void + onCancel?: () => void @Trace - onRepeat?:()=>void - constructor(option?:AnimatorType) { + onRepeat?: () => void + + constructor(option?: AnimatorType) { this.state = option?.state this.iterations = option?.iterations this.reverse = option?.reverse @@ -61,6 +64,7 @@ export class AnimatorOption { this.onRepeat = option?.onRepeat } } + interface ImageOption { // 主图资源 loadSrc: string | PixelMap | Resource @@ -69,6 +73,7 @@ interface ImageOption { // 失败占位图 errorholderSrc?: string | PixelMap | Resource headerOption?: Array; + // 自定义缓存关键字 signature?: string // 主图填充效果 @@ -88,9 +93,10 @@ interface ImageOption { progressListener?: (progress: number) => void; transformation?: PixelMapTransformation onLoadListener?: OnLoadCallBack | undefined; - onComplete?:(event:EventImage | undefined) => void + onComplete?: (event: EventImage | undefined) => void drawingColorFilter?: ColorFilter | drawing.ColorFilter } + @ObservedV2 export class ImageKnifeOption { // 主图资源 @@ -119,9 +125,10 @@ export class ImageKnifeOption { progressListener?: (progress: number) => void; @Trace transformation?: PixelMapTransformation onLoadListener?: OnLoadCallBack | undefined; - onComplete?:(event:EventImage | undefined) => void - drawingColorFilter?: ColorFilter | drawing.ColorFilter - constructor(option?:ImageOption) { + onComplete?: (event: EventImage | undefined) => void + drawingColorFilter?: ColorFilter | drawing.ColorFilter | ResourceColor + + constructor(option?: ImageOption) { this.loadSrc = option?.loadSrc == undefined ? "" : option?.loadSrc this.placeholderSrc = option?.placeholderSrc this.errorholderSrc = option?.errorholderSrc @@ -149,13 +156,14 @@ export class ImageKnifeOption { */ export interface OnLoadCallBack { // 请求开始 - onLoadStart?: () => void; + onLoadStart?: (imageKnifeData?: ImageKnifeData) => void; // 请求成功 onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData) => void; // 请求结束 - onLoadFailed?: (err: string) => void; + onLoadFailed?: (err: string, errorInfo?: ErrorInfo) => void; + // 请求取消 - onLoadCancel?: (reason: string) => void; + onLoadCancel?: (reason: string, errorInfo?: ErrorInfo) => void; } \ No newline at end of file diff --git a/library/src/main/ets/model/ImageKnifeRequest.ets b/library/src/main/ets/model/ImageKnifeRequest.ets index c63f8be..503d45f 100644 --- a/library/src/main/ets/model/ImageKnifeRequest.ets +++ b/library/src/main/ets/model/ImageKnifeRequest.ets @@ -14,7 +14,7 @@ */ import { ImageKnifeOption } from './ImageKnifeOption'; import common from '@ohos.app.ability.common'; -import { ImageKnifeRequestSource } from './ImageKnifeData'; +import { ImageKnifeData, ImageKnifeRequestSource } from './ImageKnifeData'; export class ImageKnifeRequest { @@ -26,13 +26,15 @@ export class ImageKnifeRequest { context: common.UIAbilityContext ImageKnifeRequestCallback: ImageKnifeRequestCallback componentVersion: number = 0 - headers: Map = new Map() + headers: Map = new Map() + private imageCallBackData: ImageKnifeData | undefined = undefined; + constructor(option: ImageKnifeOption, - uIAbilityContext: common.UIAbilityContext, - width: number, - height: number, - version: number, - ImageKnifeRequestCallback: ImageKnifeRequestCallback) { + uIAbilityContext: common.UIAbilityContext, + width: number, + height: number, + version: number, + ImageKnifeRequestCallback: ImageKnifeRequestCallback) { this.imageKnifeOption = option this.context = uIAbilityContext this.componentWidth = width @@ -40,6 +42,7 @@ export class ImageKnifeRequest { this.componentVersion = version this.ImageKnifeRequestCallback = ImageKnifeRequestCallback } + // RequestOption调用header对于的方法 addHeader(key: string, value: Object) { this.headers.set(key, value); @@ -53,6 +56,14 @@ export class ImageKnifeRequest { } }) } + + setImageKnifeData(data: ImageKnifeData) { + this.imageCallBackData = data; + } + + getImageKnifeData(): ImageKnifeData | undefined { + return this.imageCallBackData + } } export enum ImageKnifeRequestState { @@ -64,5 +75,6 @@ export enum ImageKnifeRequestState { export interface ImageKnifeRequestCallback { - showPixelMap: (version: number, pixelMap: PixelMap | string , requestSource: ImageKnifeRequestSource,imageAnimator?: Array) => void; + showPixelMap: (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource, + imageAnimator?: Array) => void; } diff --git a/library/src/main/ets/utils/Constants.ets b/library/src/main/ets/utils/Constants.ets index d187451..33ba0c8 100644 --- a/library/src/main/ets/utils/Constants.ets +++ b/library/src/main/ets/utils/Constants.ets @@ -14,4 +14,54 @@ */ export class Constants { public static PROGRESS_EMITTER: string = "progressEmitter" +} + +/** + * 图片加载的code + */ +export enum LoadPixelMapCode { + // createImageSource error code + IMAGE_SOURCE_ERROR_CODE = 100001, + // createPixelMap error code + IMAGE_DECODE_ERROR_CODE = 100002, + //ImageKnifeAnimatorComponent组件仅支持动态图 code + IMAGE_FORMAT_ERROR_CODE = 100003, + //load failed code + IMAGE_LOAD_FAILED_CODE = 100004, + //自定义下载失败 code + IMAGE_CUSTOM_LOAD_FAILED_CODE = 100005, + // http请求失败 code + IMAGE_HTTPS_LOAD_FAILED_CODE = 100006, + //设置onlyRetrieveFromCache 导致的加载失败的code + IMAGE_RETRIEVE_CACHE_CODE = 100007, + //加载共享图片失败 + IMAGE_LOAD_SHARE_FILE_FAILED_CODE = 100008, + //加载本地文件图片失败 + IMAGE_LOAD_LOCAL_FILE_FAILED_CODE = 100009, + // 取消请求加载code + IMAGE_LOAD_CANCEL_FAILED_CODE = 1000010 +} + +/** + * 图片加载的各个阶段 + */ +export enum LoadPhase { + // 图片加载阶段 + PHASE_LOAD = "load", + // 网络请求下载阶段 + PHASE_NET = "net", + // createPixelMap 阶段 + PHASE_CREATE_SOURCE = "createImageSource", + //createPixelMap 阶段 + PHASE_CREATE_PIXEL_MAP = "createPixelMap", + //请求队列排队阶段 + PHASE_THREAD_QUEUE = "thread_queue", + //图片解析阶段 + PHASE_PARSE_IAMGE = "parseImage", + //加载解析datashare:// 或者file:// 阶段 + PHASE_SHARE_FILE = "datashare_or_file", + //加载解析本地文件阶段 + PHASE_LOCAL_FILE = "load_local_file", + //图片加载解析完成,即将显示的阶段 + PHASE_WILL_SHOW = "will_show", } \ No newline at end of file