ImageKnife/library/src/main/ets/components/imageknife/ImageKnife.ets

843 lines
31 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DiskLruCache } from "../cache/DiskLruCache"
import { EngineKeyFactories } from "../cache/key/EngineKeyFactories"
import { EngineKeyInterface } from "../cache/key/EngineKeyInterface"
import { RequestOption, Size } from "../imageknife/RequestOption"
import { AsyncCallback } from "../imageknife/interface/AsyncCallback"
import { PlaceHolderManager } from "../imageknife/holder/PlaceHolderManager"
import { RetryHolderManager } from "../imageknife/holder/RetryHolderManager"
import { ErrorHolderManager } from "../imageknife/holder/ErrorHolderManager"
import { RequestManager } from "../imageknife/requestmanage/RequestManager"
import { NONE } from "../cache/diskstrategy/enum/NONE"
import { FileTypeUtil } from '../imageknife/utils/FileTypeUtil'
import { DownloadClient } from '../imageknife/networkmanage/DownloadClient'
import { IDataFetch } from '../imageknife/networkmanage/IDataFetch'
import { ParseResClient } from '../imageknife/resourcemanage/ParseResClient'
import { IResourceFetch } from '../imageknife/resourcemanage/IResourceFetch'
import { ImageKnifeData, ImageKnifeType } from '../imageknife/ImageKnifeData'
import { ImageKnifeGlobal } from '../imageknife/ImageKnifeGlobal'
import image from "@ohos.multimedia.image"
import { CompressBuilder } from "../imageknife/compress/CompressBuilder"
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
import { LogUtil } from '../imageknife/utils/LogUtil'
import { EasyLinkedHashMap } from './utils/base/EasyLinkedHashMap'
import { MethodMutex } from './utils/base/MethodMutex'
import worker from '@ohos.worker'
import common from '@ohos.app.ability.common'
import { MemoryLruCache } from '../cache/MemoryLruCache'
import { BusinessError } from '@ohos.base'
import taskpool from '@ohos.taskpool'
import { GIFFrame } from './utils/gif/GIFFrame'
import emitter from '@ohos.events.emitter';
import { MemoryCacheProxy } from './requestmanage/MemoryCacheProxy'
import { ObjectKey } from './ObjectKey'
import { TaskParams } from './TaskParams'
import { Constants } from './constants/Constants'
import { TransformUtils } from './transform/TransformUtils'
export class ImageKnife {
static readonly SEPARATOR: string = '/'
memoryCache: MemoryLruCache;
dataFetch: IDataFetch;
resourceFetch: IResourceFetch<ArrayBuffer>;
filesPath: string = ""; // data/data/包名/files目录
diskMemoryCache: DiskLruCache;
memoryCacheProxy: MemoryCacheProxy<string, ImageKnifeData> = new MemoryCacheProxy(new MemoryLruCache(100, 100 * 1024 * 1024));
headerMap: Map<string, Object> = new Map<string, Object>(); //定义全局map
placeholderCache: string = "placeholderCache"
runningMaps: EasyLinkedHashMap<string, RequestOption>;
pendingMaps: EasyLinkedHashMap<string, RequestOption>;
pausedMaps: EasyLinkedHashMap<string, RequestOption>;
isPaused: boolean = false;
mutex: MethodMutex = new MethodMutex();
fileTypeUtil: FileTypeUtil; // 通用文件格式辨别
diskCacheFolder: string = "ImageKnifeDiskCache"
defaultListener: AsyncCallback<ImageKnifeData> = {
callback: (err: string, data: ImageKnifeData) => {
return false
}
}; // 全局监听器
// gifWorker
gifWorker: worker.ThreadWorker | undefined = undefined;
defaultLifeCycle: IDrawLifeCycle | undefined = undefined;
// 开发者可配置全局缓存
engineKeyImpl: EngineKeyInterface;
private constructor() {
this.runningMaps = new EasyLinkedHashMap();
this.pendingMaps = new EasyLinkedHashMap();
this.pausedMaps = new EasyLinkedHashMap();
// 构造方法传入size 为保存文件个数
this.memoryCache = new MemoryLruCache(100, 100 * 1024 * 1024);
// 创建网络下载能力
this.dataFetch = new DownloadClient();
// 创建本地数据解析能力
this.resourceFetch = new ParseResClient();
// 初始化本地 文件保存
this.filesPath = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string;
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext);
// 通用文件格式识别初始化
this.fileTypeUtil = new FileTypeUtil();
this.engineKeyImpl = new EngineKeyFactories();
}
//全局设置请求头调用方法
addHeader(key: string, value: Object) {
this.headerMap.set(key, value);
}
deleteHeader(key: string) {
this.headerMap.delete(key);
}
getMemoryCache(): MemoryLruCache {
return this.memoryCache;
}
getMemoryCacheProxy(): MemoryCacheProxy<string, ImageKnifeData> {
return this.memoryCacheProxy;
}
public static with(context: Object): ImageKnifeGlobal {
// 存入hapContext;
let global: ImageKnifeGlobal = ImageKnifeGlobal.getInstance();
global.setHapContext(context)
// 初始化ImageKnife
if (!ImageKnife.sInstance) {
ImageKnife.sInstance = new ImageKnife();
}
// 存入ImageKnife
global.setImageKnife(ImageKnife.sInstance)
return global;
}
getDiskMemoryCache(): DiskLruCache {
return this.diskMemoryCache;
};
setDiskMemoryCache(diskLruCache: DiskLruCache) {
this.diskMemoryCache = diskLruCache;
};
getFileTypeUtil(): FileTypeUtil {
return this.fileTypeUtil;
}
getImageKnifeContext() {
return ImageKnifeGlobal.getInstance().getHapContext();
}
setMemoryCache(lrucache: MemoryLruCache) {
this.memoryCache = lrucache;
}
getDefaultListener() {
return this.defaultListener;
}
setGifWorker(worker: worker.ThreadWorker) {
this.gifWorker = worker
}
getGifWorker() {
return this.gifWorker;
}
getDefaultLifeCycle() {
return this.defaultLifeCycle;
}
setDefaultLifeCycle(viewLifeCycle: IDrawLifeCycle) {
this.defaultLifeCycle = viewLifeCycle;
}
setEngineKeyImpl(impl: EngineKeyInterface) {
this.engineKeyImpl = impl;
}
private static sInstance: ImageKnife;
setDefaultListener(newDefaultListener: AsyncCallback<ImageKnifeData>) {
this.defaultListener = newDefaultListener;
}
public compressBuilder(): CompressBuilder {
return new CompressBuilder();
}
// 设置缓存张数,缓存大小,单位字节
public setLruCacheSize(size: number, memory: number) {
if (this.memoryCache.map.size() <= 0) {
this.memoryCache = new MemoryLruCache(size, memory);
} else {
let newLruCache = new MemoryLruCache(size, memory);
this.memoryCache.foreachLruCache((value: ImageKnifeData, key: string, map: Object) => {
newLruCache.put(key, value);
})
this.memoryCache = newLruCache;
}
}
public replaceDataFetch(fetch: IDataFetch) {
this.dataFetch = fetch;
}
// 替代原来的DiskLruCache
public replaceDiskLruCache(size: number) {
this.diskMemoryCache.setMaxSize(size)
// if (this.diskMemoryCache.getCacheMap().size() <= 0) {
// this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
// } else {
// let newDiskLruCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
// this.diskMemoryCache.foreachDiskLruCache((value: string | ArrayBuffer, key: string, map: Object) => {
// newDiskLruCache.set(key, value);
// })
// this.diskMemoryCache = newDiskLruCache;
// }
}
// 预加载 resource资源一级缓存string资源实现二级缓存
preload(request: RequestOption): void {
// 每个request 公共信息补充
request.setFilesPath(this.filesPath);
return this.parseSource(request);
}
// 暂停所有请求
async pauseRequests(): Promise<void> {
await this.mutex.lock(async () => {
this.isPaused = true;
// 将未删除的所有request [run pend] 放入 [pause]
LogUtil.log('dodo pauseRequests start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
// 将run存入pause
let runNode = this.runningMaps.getHead();
while (runNode) {
let request = runNode.value;
this.pausedMaps.put(request.uuid, request)
runNode = runNode.next;
}
this.runningMaps.clear();
LogUtil.log('dodo pauseRequests start2 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
let pendNode = this.pendingMaps.getHead();
while (pendNode) {
let request = pendNode.value;
this.pausedMaps.put(request.uuid, request)
pendNode = pendNode.next
}
this.pendingMaps.clear()
LogUtil.log('dodo pauseRequests start3 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
})
}
// 恢复所有被暂停的请求
async resumeRequests(): Promise<void> {
await this.mutex.lock(async () => {
this.isPaused = false;
LogUtil.log('dodo resumeRequest start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
// 重启了之后需要把paused 里面的所有request重新发送
let headNode = this.pausedMaps.getHead();
while (headNode) {
let request = headNode.value
this.loadCacheManager(request)
headNode = headNode.next
}
this.pausedMaps.clear()
LogUtil.log('dodo resumeRequest start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
})
}
// 删除 请求
remove(uuid: string) {
if (this.isPaused) {
this.pausedMaps.remove(uuid)
} else {
// TODO 哪些请求可以删除
this.pendingMaps.remove(uuid)
this.runningMaps.remove(uuid)
}
}
// 正常加载
call(request: RequestOption): void {
// 添加全局监听
if (this.defaultListener) {
request.addListener(this.defaultListener)
}
// 每个request 公共信息补充
request.setFilesPath(this.filesPath);
if (this.headerMap.size > 0) {
request.addHeaderMap(this.headerMap)
}
this.generateDataCacheKey(request)
// 首先执行占位图 解析任务
if (request.placeholderSrc) {
this.taskpoolLoadResource(request, Constants.PLACE_HOLDER);
}
// 其次执行重试占位图 解析任务
if (request.retryholderSrc) {
this.taskpoolLoadResource(request, Constants.RETRY_HOLDER);
}
// 最后解析错误占位图
if (request.errorholderSrc) {
this.taskpoolLoadResource(request, Constants.ERROR_HOLDER);
}
return this.parseSource(request);
}
generateDataCacheKey(request: RequestOption) {
let factories: EngineKeyInterface;
let cacheKey: string;
let transferKey: string;
let dataKey: string;
//设置全局缓存key
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
// 生成内存缓存key 内存 变换后磁盘
let loadKey = '';
if (typeof request.loadSrc == 'string') {
loadKey = request.loadSrc;
} else {
loadKey = JSON.stringify(request.loadSrc);
}
let size = JSON.stringify(request.size);
let transformed = '';
if (request && request.transformations) {
for (let i = 0; i < request.transformations.length; i++) {
if (i == request.transformations.length - 1) {
transformed += request.transformations[i].getName() + "";
} else {
transformed += request.transformations[i].getName() + ",";
}
}
}
let dontAnimateFlag = request.dontAnimateFlag;
let signature = request.signature;
cacheKey = factories.generateMemoryCacheKey(loadKey, size, transformed, dontAnimateFlag, signature);
// 生成磁盘缓存变换后数据key 变换后数据保存在磁盘
transferKey = factories.generateTransformedDiskCacheKey(loadKey, size, transformed, dontAnimateFlag, signature);
// 生成磁盘缓存源数据key 原始数据保存在磁盘
dataKey = factories.generateOriginalDiskCacheKey(loadKey, signature);
if (request.placeholderSrc) {
let placeholderLoadKey = '';
if (typeof request.placeholderSrc == 'string') {
placeholderLoadKey = request.placeholderSrc;
} else {
placeholderLoadKey = JSON.stringify(request.placeholderSrc);
}
request.placeholderCacheKey = this.generateCacheKey(placeholderLoadKey, size, dontAnimateFlag, signature)
}
if (request.retryholderSrc) {
let retryholderLoadKey = '';
if (typeof request.retryholderSrc == 'string') {
retryholderLoadKey = request.retryholderSrc;
} else {
retryholderLoadKey = JSON.stringify(request.retryholderSrc);
}
request.retryholderCacheKey = this.generateCacheKey(retryholderLoadKey, size, dontAnimateFlag, signature)
}
if (request.errorholderSrc) {
let errorholderLoadKey = '';
if (typeof request.errorholderSrc == 'string') {
errorholderLoadKey = request.errorholderSrc;
} else {
errorholderLoadKey = JSON.stringify(request.errorholderSrc);
}
request.errorholderCacheKey = this.generateCacheKey(errorholderLoadKey, size, dontAnimateFlag, signature)
}
request.generateCacheKey = cacheKey;
request.generateResourceKey = transferKey;
request.generateDataKey = dataKey;
}
private generateCacheKey(loadkey: string, size: string, dontAnimateFlag: boolean, signature?: ObjectKey) {
let factories: EngineKeyInterface;
//设置全局缓存key
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
return factories.generateMemoryCacheKey(loadkey, size, '', dontAnimateFlag, signature);
}
// 删除执行结束的running
removeRunning(request: RequestOption) {
if (this.isPaused) {
} else {
this.runningMaps.remove(request.uuid);
LogUtil.log('dodo runningMaps length =' + this.runningMaps.size())
let previousRequest = request;
this.loadNextPending(previousRequest);
}
}
// 执行相同key的pending队列请求
private keyEqualPendingToRun(nextPending: RequestOption) {
this.pendingMaps.remove(nextPending.uuid)
this.runningMaps.put(nextPending.uuid, nextPending);
// RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
this.taskpoolLoadResource(nextPending, Constants.MAIN_HOLDER);
}
private searchNextKeyToRun() {
// 其次则寻找pending中第一个和running不重复的requestOrKey
let pendingTailNode = this.pendingMaps.getTail();
while (pendingTailNode) {
let pendingRequest = pendingTailNode.value;
let hasEqual = false;
let runningTailNode = this.runningMaps.getTail();
while (runningTailNode) {
let runningRequest = runningTailNode.value;
if (this.requestOrKeyEqual(pendingRequest, runningRequest)) {
hasEqual = true;
break
}
runningTailNode = runningTailNode.prev;
}
if (!hasEqual) {
break;
}
pendingTailNode = pendingTailNode.prev;
}
if (pendingTailNode != null && pendingTailNode.value != null) {
let nextPending = pendingTailNode.value;
this.runningMaps.put(nextPending.uuid, nextPending)
this.pendingMaps.remove(nextPending.uuid)
//RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
this.taskpoolLoadResource(nextPending, Constants.MAIN_HOLDER);
}
}
// 加载下一个key的请求
private loadNextPending(request: RequestOption) {
let hasEqualRunning = false;
let tailNode = this.pendingMaps.getTail();
while (tailNode) {
if (this.requestOrKeyEqual(request, tailNode.value)) {
hasEqualRunning = true;
break;
}
tailNode = tailNode.prev;
}
if (hasEqualRunning) {
if (tailNode != null && tailNode.value != null) {
this.keyEqualPendingToRun(tailNode.value);
}
} else {
this.searchNextKeyToRun();
}
}
// 启动新线程 去磁盘取 去网络取
private loadCacheManager(request: RequestOption) {
if (this.isPaused) {
// 将当前request存入pausedMaps
this.pausedMaps.put(request.uuid, request);
} else {
// 正常逻辑
if (this.keyNotEmpty(request)) {
let hasRunningRequest = false;
// 遍历双向链表 从尾巴到头
let tailNode = this.runningMaps.getTail();
while (tailNode) {
if (this.requestOrKeyEqual(request, tailNode.value)) {
hasRunningRequest = true;
break;
}
tailNode = tailNode.prev
}
if (hasRunningRequest) {
this.pendingMaps.put(request.uuid, request);
} else {
this.runningMaps.put(request.uuid, request)
this.taskpoolLoadResource(request, Constants.MAIN_HOLDER);
}
}
else {
LogUtil.log("key没有生成无法进入存取")
}
}
}
//组装任务参数
private assembleTaskParams(request: RequestOption, usageType: string) {
//图片变换方法无法直接传递到子线程,这里先把对象名和构造参数传递到子线程,然后在子线程中实例化变换方法
let transformations: string [][] = [];
if (usageType == Constants.MAIN_HOLDER) {
for (let i = 0; i < request.transformations.length; i++) {
transformations.push([request.transformations[i].getClassName(), request.transformations[i].getConstructorParams()])
}
}
let displayProgress = request.progressFunc ? true : false;
//將要传递到子线程的参数放在一个json对象上避免方法参数过多
let taskParams: TaskParams = {
headers: request.headers,
moduleContext: request.moduleContext,
transformations: transformations,
usageType: usageType,
displayProgress: displayProgress,
uuid: request.uuid,
dontAnimateFlag: request.dontAnimateFlag,
priority: request.priority,
generateCacheKey: request.generateCacheKey,
generateResourceKey: request.generateResourceKey,
generateDataKey: request.generateDataKey,
thumbSizeMultiplier: request.thumbSizeMultiplier,
thumbDelayTime: request.thumbDelayTime,
size: request.size,
onlyRetrieveFromCache: request.onlyRetrieveFromCache,
gpuEnabled: request.gpuEnabled,
signature: request.signature,
isCacheable: request.isCacheable,
diskMemoryCachePath: this.diskMemoryCache.getPath()
}
return taskParams;
}
//多线程请求加载资源
private taskpoolLoadResource(request: RequestOption, usageType: string) {
let mainCache = this.memoryCacheProxy.loadMemoryCache(request.generateCacheKey, request.isCacheable);
let placeholderCache = this.memoryCacheProxy.loadMemoryCache(request.placeholderCacheKey, request.isCacheable);
let retryholderCache = this.memoryCacheProxy.loadMemoryCache(request.retryholderCacheKey, request.isCacheable);
let errorholderCacheKey = this.memoryCacheProxy.loadMemoryCache(request.errorholderCacheKey, request.isCacheable);
if (usageType == Constants.PLACE_HOLDER && placeholderCache && !mainCache && !retryholderCache && !errorholderCacheKey) {
LogUtil.info("imageknife load placeholder from MemoryCache")
request.placeholderOnComplete(placeholderCache);
return;
} else if (usageType == Constants.RETRY_HOLDER && retryholderCache && !mainCache && !errorholderCacheKey) {
LogUtil.info("imageknife load retryholder from MemoryCache")
request.retryholderOnComplete(retryholderCache);
return;
} else if (usageType == Constants.ERROR_HOLDER && errorholderCacheKey && !mainCache) {
LogUtil.info("imageknife load errorholder from MemoryCache")
request.errorholderOnComplete(errorholderCacheKey);
return;
} else if (usageType == Constants.MAIN_HOLDER && mainCache) {
LogUtil.info("imageknife load mainsource from MemoryCache")
mainCache.waitSaveDisk = false;
request.loadComplete(mainCache);
return;
}
let taskParams: TaskParams = this.assembleTaskParams(request, usageType);
let loadSrcJson = JSON.stringify({
loadSrc: request.loadSrc,
placeholderSrc: request.placeholderSrc,
errorholderSrc: request.errorholderSrc,
retryholderSrc: request.retryholderSrc,
});
//使用taskpool多线程执行资源下载
let task: ESObject = new taskpool.Task(taskExecute, taskParams, loadSrcJson)
task.setTransferList([])
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);
}
});
taskpool.execute(task,request.priority).then((data: ESObject) => {
if (usageType == Constants.PLACE_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.placeholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.placeholderCacheKey,imageKnifeData)
} else {
request.placeholderOnError("request placeholder error")
}
} else if (usageType == Constants.RETRY_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.retryholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.retryholderCacheKey,imageKnifeData)
} else {
request.retryholderOnError("request retryholder error")
}
} else if (usageType == Constants.ERROR_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.errorholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.errorholderCacheKey,imageKnifeData)
} else {
request.errorholderOnError("request errorholder error")
}
} else {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
imageKnifeData.needSaveDisk = true;
request.loadComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.generateCacheKey,imageKnifeData)
this.setDiskCache(request)
} else if ((data as GIFFrame[]).length > 0) {
let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data as GIFFrame[]);
imageKnifeData.needSaveDisk = true;
request.loadComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.generateCacheKey,imageKnifeData)
this.setDiskCache(request)
} else {
request.loadError("request resources error")
}
}
}).catch((err: BusinessError | string) => {
request.loadError(err)
})
}
private setDiskCache(request: RequestOption):void{
try {
// let diskMemoryCache = ImageKnifeGlobal.getInstance().getImageKnife()?.getDiskMemoryCache();
let dataArraybuffer: ArrayBuffer = DiskLruCache.getFileCacheByFile(this.diskMemoryCache.getPath() as string, request.generateDataKey) as ArrayBuffer;
//缓存原图片
if (dataArraybuffer) {
this.diskMemoryCache.setCacheMapAndSize(request.generateDataKey, dataArraybuffer);
}
//缓存变换后图片
let resourceArraybuffer: ArrayBuffer = DiskLruCache.getFileCacheByFile(this.diskMemoryCache.getPath() as string, request.generateResourceKey) as ArrayBuffer;
if (resourceArraybuffer) {
this.diskMemoryCache.setCacheMapAndSize(request.generateResourceKey, resourceArraybuffer);
}
} catch (e) {
LogUtil.error("imageknife DiskMemoryCache setDiskCache error :" + e.message);
}
}
private keyNotEmpty(request: RequestOption): boolean {
if (
request.generateCacheKey != null && request.generateCacheKey.length > 0 &&
request.generateDataKey != null && request.generateDataKey.length > 0 &&
request.generateResourceKey != null && request.generateResourceKey.length > 0
) {
return true;
}
return false;
}
private keyEqual(request1: RequestOption, request2: RequestOption): boolean {
// key 完全相等的情况
if (
request1.generateCacheKey == request2.generateCacheKey &&
request1.generateResourceKey == request2.generateResourceKey &&
request1.generateDataKey == request2.generateDataKey
) {
return true;
}
return false;
}
// 非严格校验模式,如果所有key相等我们认为一定相等, 如果请求类型是string 网络请求url或者uri相等 我们也认为该请求应该只发送一个即可,后续请求会去缓存或者磁盘读取
private requestOrKeyEqual(request1: RequestOption, request2: RequestOption): boolean {
// key 完全相等的情况
if (
request1.generateCacheKey == request2.generateCacheKey &&
request1.generateResourceKey == request2.generateResourceKey &&
request1.generateDataKey == request2.generateDataKey
) {
return true;
}
// 如果加载的是网络url或者是本地文件uri读取,那么loadSrc相同就认为是同一个请求
if (
typeof request1.loadSrc == 'string' && typeof request2.loadSrc == 'string' && request1.loadSrc == request2.loadSrc
) {
return true;
}
return false;
}
private parseSource(request: RequestOption): void {
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, request.loadSrc as PixelMap)
request.loadComplete(imageKnifeData);
} else if (typeof request.loadSrc == 'string') {
// 进入三级缓存模型
return this.loadCacheManager(request);
} else {
let res = request.loadSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.type != 'undefined') {
// 进入三级缓存模型 本地资源不参与磁盘缓存
let none = new NONE();
request.diskCacheStrategy(none);
this.loadCacheManager(request);
} else {
LogUtil.error("输入参数有问题!")
}
}
}
prefetchToDiskCache(url: string): Promise<string> {
return new Promise((resolve, reject) => {
let key = this.engineKeyImpl.generateOriginalDiskCacheKey(url, undefined);
let cachedPath = this.getDiskMemoryCache().getFileToPath(key);
if (cachedPath == null || cachedPath == "" || cachedPath == undefined) {
let request = new RequestOption();
request.load(url)
.addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => {
if (err) {
reject(err)
} else {
let cachedPath = this.getDiskMemoryCache().getFileToPath(key);
resolve(cachedPath);
}
return false;
}
})
this.call(request);
} else {
resolve(cachedPath);
}
})
}
}
/**
* 加载资源子线程包含流程:网络请求资源->下载资源到本地->解码成ixelMap | GIFFrame[]->缓存到内存和磁盘
* @param taskParams:任务参数JSON字符串类型
* @param headers请求头
* @param moduleContext模块上下文
* @returns
*/
@Concurrent
async function taskExecute(taskParams: TaskParams, loadSrcJson: string): Promise<PixelMap | GIFFrame[]> {
let emitProgressPercent = (percentValue: number) => {
let eventData: emitter.EventData = {
data: {
"value": percentValue,
}
};
emitter.emit(Constants.PROGRESS_EMITTER as ESObject, eventData)
}
let transformations = taskParams.transformations;
let usageType = taskParams.usageType;
let displayProgress = taskParams.displayProgress;
//子线程构造RequestOption对象
let newRequestOption = new RequestOption();
let loadSrcObj: object = JSON.parse(loadSrcJson);
newRequestOption.priority = taskParams.priority
newRequestOption.uuid = taskParams.uuid;
newRequestOption.loadSrc = loadSrcObj["loadSrc"] as string | PixelMap | Resource;
newRequestOption.dontAnimateFlag = taskParams.dontAnimateFlag;
newRequestOption.generateCacheKey = taskParams.generateCacheKey;
newRequestOption.generateResourceKey = taskParams.generateResourceKey;
newRequestOption.generateDataKey = taskParams.generateDataKey;
newRequestOption.thumbSizeMultiplier = taskParams.thumbSizeMultiplier;
newRequestOption.thumbDelayTime = taskParams.thumbDelayTime;
newRequestOption.size = taskParams.size;
newRequestOption.diskMemoryCachePath = taskParams.diskMemoryCachePath;
newRequestOption.placeholderSrc = loadSrcObj["placeholderSrc"] as PixelMap | Resource | undefined;
newRequestOption.errorholderSrc = loadSrcObj["errorholderSrc"] as PixelMap | Resource | undefined;
newRequestOption.retryholderSrc = loadSrcObj["retryholderSrc"] as PixelMap | Resource | undefined;
newRequestOption.onlyRetrieveFromCache = taskParams.onlyRetrieveFromCache;
newRequestOption.gpuEnabled = taskParams.gpuEnabled;
newRequestOption.headers = taskParams.headers;
newRequestOption.signature = taskParams.signature;
ImageKnifeGlobal.getInstance().setHapContext(taskParams.moduleContext as common.UIAbilityContext);
newRequestOption.moduleContext = taskParams.moduleContext;
newRequestOption.isCacheable = taskParams.isCacheable;
if (displayProgress) {
newRequestOption.addProgressListener({
asyncSuccess: (percentValue: number) => {
// 如果进度条百分比 未展示大小,展示其动画
emitProgressPercent(percentValue)
}
})
}
//如果是本地图片不作磁盘缓存
if (typeof newRequestOption.loadSrc !== 'string') {
let none = new NONE();
newRequestOption.diskCacheStrategy(none);
}
if (usageType == Constants.PLACE_HOLDER) {
let manager = new PlaceHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == Constants.RETRY_HOLDER) {
let manager = new RetryHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == Constants.ERROR_HOLDER) {
let manager = new ErrorHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else {
if (transformations) {
newRequestOption.setTransformations(TransformUtils.addTransformations(transformations))
}
let newDataFetch = new DownloadClient();
let newResourceFetch = new ParseResClient();
let manager = new RequestManager(newRequestOption, newDataFetch, newResourceFetch);
return await new Promise<PixelMap | GIFFrame[]>(manager.process);
}
}