1.修改memorykey生成

2.文件缓存key由子线程生成,返回到主线程管理

Signed-off-by: madixin <madixin@huawei.com>
This commit is contained in:
madixin 2024-05-03 20:36:15 +08:00
parent 33ba458600
commit 91634663dc
11 changed files with 109 additions and 163 deletions

View File

@ -138,22 +138,22 @@ ImageKnifeComponent({ ImageKnifeOption:
## 接口说明 ## 接口说明
### ImageKnifeOption参数列表 ### ImageKnifeOption参数列表
| 参数名称 | 入参内容 | 功能简介 | | 参数名称 | 入参内容 | 功能简介 |
|-----------------------|-------------------------------|-----------------| |-----------------------|--------------------------------|-----------------|
| loadSrc | string、PixelMap、Resource | 主图展示 | | loadSrc | string、PixelMap、Resource | 主图展示 |
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) | | placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) | | errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
| objectFit | ImageFit | 图片展示样式(可选) | | objectFit | ImageFit | 图片展示样式(可选) |
| writeCacheStrategy | WriteCacheStrategyType | 写入缓存策略(可选) | | writeCacheStrategy | WriteCacheStrategyType | 写入缓存策略(可选) |
| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) | | onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) |
| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 | | customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 |
| border | BorderOptions | 边框圆角(可选) | | border | BorderOptions | 边框圆角(可选) |
| priority | taskpool.Priority | 加载优先级(可选) | | priority | taskpool.Priority | 加载优先级(可选) |
| context | common.UIAbilityContext | 上下文(可选) | | context | common.UIAbilityContext | 上下文(可选) |
| progressListener | (progress: number)=>void | 进度(可选) | | progressListener | (progress: number)=>void | 进度(可选) |
| signature | ObjectKey | 自定义缓存关键字(可选) | | signature | String | 自定义缓存关键字(可选) |
| headerOption | Array<HeaderOptions> | 设置请求头(可选) | | headerOption | Array<HeaderOptions> | 设置请求头(可选) |
| transformation | PixelMapTransformation | 图片变换(可选) | | transformation | PixelMapTransformation | 图片变换(可选) |
### ImageKnife接口 ### ImageKnife接口
| 参数名称 | 入参内容 | 功能简介 | | 参数名称 | 入参内容 | 功能简介 |

View File

@ -12,46 +12,35 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import util from '@ohos.util'; import { IEngineKey, ImageKnifeOption, PixelMapTransformation } from '@ohos/imageknife';
import { IEngineKey, ImageKnifeOption, ObjectKey , PixelMapTransformation } from '@ohos/imageknife';
import { SparkMD5 } from '@ohos/imageknife/src/main/ets/3rd_party/sparkmd5/spark-md5'; import { SparkMD5 } from '@ohos/imageknife/src/main/ets/3rd_party/sparkmd5/spark-md5';
import { ImageKnifeRequestSource } from '@ohos/imageknife/src/main/ets/ImageKnifeDispatcher';
//全局自定义key demo //全局自定义key demo
@Sendable
export class CustomEngineKeyImpl implements IEngineKey { export class CustomEngineKeyImpl implements IEngineKey {
private memoryKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
private fileKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
// 生成内存缓存key // 生成内存缓存key
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string { generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";" imageKnifeOption: ImageKnifeOption, width?: number, height?: number): string {
if (imageKnifeOption.signature) { let key = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
src += "signature=" + imageKnifeOption.signature.getKey() + ";" if (requestSource === ImageKnifeRequestSource.SRC) {
if (imageKnifeOption.signature !== undefined && imageKnifeOption.signature !== "") {
key += "signature=" + imageKnifeOption.signature + ";"
}
if (imageKnifeOption.transformation) {
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
}
} }
if (imageKnifeOption.transformation) { return key
src += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
}
return this.generateKey(src, this.memoryKeyCache)
} }
// 生成文件缓存key // 生成文件缓存key
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string { generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string): string {
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";" let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
if (signature) { if (signature !== undefined && signature !== "") {
src += "signature=" + signature.getKey() + ";" src += "signature=" + signature + ";"
}
return this.generateKey(src, this.fileKeyCache)
}
// key缓存策略避免无意义的 JSON.stringify
private generateKey(keyCache: string, cache: util.LRUCache<string, string>): string {
let result = cache.get(keyCache)
if (result != undefined) {
return result
} else {
result = SparkMD5.hashBinary(keyCache)
cache.put(keyCache, result)
return result
} }
return SparkMD5.hashBinary(src)
} }
private getTransformation(transformation: PixelMapTransformation): string { private getTransformation(transformation: PixelMapTransformation): string {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021 Huawei Device Co., Ltd. * Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeComponent, ImageKnifeOption, ObjectKey } from '@ohos/imageknife'; import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife';
@Entry @Entry
@ -40,7 +40,7 @@ struct SignatureTestPage {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r("app.media.loading"),
signature: new ObjectKey("1") signature: "1"
} }
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
@ -53,7 +53,7 @@ struct SignatureTestPage {
this.imageKnifeOption2 = { this.imageKnifeOption2 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r("app.media.loading"),
signature: new ObjectKey(new Date().getTime().toString()) signature: new Date().getTime().toString()
} }
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
@ -66,7 +66,7 @@ struct SignatureTestPage {
} }
aboutToAppear() { aboutToAppear() {
console.log("唯一标识页面:" + new ObjectKey(new Date().getTime().toString()).getKey()) console.log("唯一标识页面:" + new Date().getTime().toString())
} }
} }

View File

@ -12,8 +12,6 @@ export { LogUtil } from './src/main/ets/utils/LogUtil'
export { IEngineKey } from './src/main/ets/key/IEngineKey' export { IEngineKey } from './src/main/ets/key/IEngineKey'
export { ObjectKey } from './src/main/ets/model/ObjectKey'
export { ImageKnifeData , ReadCacheStrategyType} from "./src/main/ets/model/ImageKnifeData" export { ImageKnifeData , ReadCacheStrategyType} from "./src/main/ets/model/ImageKnifeData"
export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation' export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation'

View File

@ -17,7 +17,7 @@ import { ReadCacheStrategyType, ImageKnifeData } from './model/ImageKnifeData';
import { MemoryLruCache } from './utils/MemoryLruCache'; import { MemoryLruCache } from './utils/MemoryLruCache';
import { IMemoryCache } from './utils/IMemoryCache' import { IMemoryCache } from './utils/IMemoryCache'
import { FileCache } from './utils/FileCache'; import { FileCache } from './utils/FileCache';
import { ImageKnifeDispatcher } from './ImageKnifeDispatcher'; import { ImageKnifeDispatcher, ImageKnifeRequestSource } from './ImageKnifeDispatcher';
import { IEngineKey } from './key/IEngineKey'; import { IEngineKey } from './key/IEngineKey';
import { HeaderOptions, ImageKnifeOption } from './ImageKnifeOption'; import { HeaderOptions, ImageKnifeOption } from './ImageKnifeOption';
import { DefaultEngineKey } from './key/DefaultEngineKey'; import { DefaultEngineKey } from './key/DefaultEngineKey';
@ -120,17 +120,17 @@ export class ImageKnife {
return this.fileCache as FileCache return this.fileCache as FileCache
} }
/** /**
* 预加载到缓存 * 预加载到文件缓存
* @param loadSrc 图片地址url * @param loadSrc 图片地址url
* @returns 返回文件缓存路径 * @returns 返回文件缓存路径
*/ */
preLoadCache(loadSrc:string): Promise<string> { preLoadCache(loadSrc: string): Promise<string> {
return new Promise((resolve,reject)=>{ return new Promise((resolve,reject)=>{
let imageKnifeOption = new ImageKnifeOption() let imageKnifeOption = new ImageKnifeOption()
imageKnifeOption.loadSrc = loadSrc imageKnifeOption.loadSrc = loadSrc
let engineKeyImpl: IEngineKey = new DefaultEngineKey() let engineKeyImpl: IEngineKey = new DefaultEngineKey()
let keys = engineKeyImpl.generateMemoryKey(loadSrc, imageKnifeOption) let fileKey = engineKeyImpl.generateFileKey(loadSrc)
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(keys) let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(fileKey)
if(cachePath == null || cachePath == "" || cachePath == undefined) { if(cachePath == null || cachePath == "" || cachePath == undefined) {
let request = new ImageKnifeRequest( let request = new ImageKnifeRequest(
imageKnifeOption, imageKnifeOption,
@ -140,7 +140,7 @@ export class ImageKnife {
0, 0,
{ {
showPixelMap(version: number, pixelMap: PixelMap | string) { showPixelMap(version: number, pixelMap: PixelMap | string) {
resolve(ImageKnife.getInstance().getFileCache().getFileToPath(keys)) resolve(ImageKnife.getInstance().getFileCache().getFileToPath(fileKey))
} }
} }
) )
@ -176,9 +176,9 @@ export class ImageKnife {
} }
private readMemoryCache(loadSrc: string,option: ImageKnifeOption, engineKey: IEngineKey): ImageKnifeData | undefined { private readMemoryCache(loadSrc: string,option: ImageKnifeOption, engineKey: IEngineKey): ImageKnifeData | undefined {
let keys = engineKey.generateMemoryKey(loadSrc,option) let memoryKey = engineKey.generateMemoryKey(loadSrc, ImageKnifeRequestSource.SRC, option)
return ImageKnife.getInstance() return ImageKnife.getInstance()
.loadFromMemoryCache(keys) .loadFromMemoryCache(memoryKey)
} }
private readFileCache(loadSrc:string,engineKey:IEngineKey,onComplete:(data:ImageKnifeData | undefined)=>void){ private readFileCache(loadSrc:string,engineKey:IEngineKey,onComplete:(data:ImageKnifeData | undefined)=>void){

View File

@ -44,11 +44,11 @@ export class ImageKnifeDispatcher {
// 执行中的请求 // 执行中的请求
executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap(); executingJobMap: LightWeightMap<string, List<ImageKnifeRequestWithSource>> = new LightWeightMap();
// 开发者可配置全局缓存 // 开发者可配置全局缓存
private engineKeyImpl: IEngineKey = new DefaultEngineKey(); private engineKey: IEngineKey = new DefaultEngineKey();
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): boolean { showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): boolean {
let memoryCache: ImageKnifeData | undefined = ImageKnife.getInstance() let memoryCache: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, request.imageKnifeOption)) .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption))
if (memoryCache !== undefined) { if (memoryCache !== undefined) {
// 画主图 // 画主图
if (request.requestState === ImageKnifeRequestState.PROGRESS) { if (request.requestState === ImageKnifeRequestState.PROGRESS) {
@ -97,13 +97,12 @@ export class ImageKnifeDispatcher {
* 获取和显示图片 * 获取和显示图片
*/ */
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): void { getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): void {
let keyMemory: string = this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.imageKnifeOption) let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc,requestSource, currentRequest.imageKnifeOption)
let keyFile: string = this.engineKeyImpl.generateFileKey(imageSrc, currentRequest.imageKnifeOption.signature) let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(keyMemory)
if (requestList == undefined) { if (requestList == undefined) {
requestList = new List() requestList = new List()
requestList.add({ request: currentRequest, source: requestSource }) requestList.add({ request: currentRequest, source: requestSource })
this.executingJobMap.set(keyMemory, requestList) this.executingJobMap.set(memoryKey, requestList)
} else { } else {
requestList.add({ request: currentRequest, source: requestSource }) requestList.add({ request: currentRequest, source: requestSource })
return return
@ -112,13 +111,14 @@ export class ImageKnifeDispatcher {
let request: RequestJobRequest = { let request: RequestJobRequest = {
context: currentRequest.context, context: currentRequest.context,
src: imageSrc, src: imageSrc,
key: keyFile,
headers:currentRequest.imageKnifeOption.headerOption, headers:currentRequest.imageKnifeOption.headerOption,
allHeaders:currentRequest.headers, allHeaders:currentRequest.headers,
customGetImage: currentRequest.imageKnifeOption.customGetImage, customGetImage: currentRequest.imageKnifeOption.customGetImage,
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache, onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
transformation:currentRequest.imageKnifeOption.transformation, transformation:currentRequest.imageKnifeOption.transformation,
writeCacheStrategy: currentRequest.imageKnifeOption.writeCacheStrategy, writeCacheStrategy: currentRequest.imageKnifeOption.writeCacheStrategy,
engineKey: this.engineKey,
signature: currentRequest.imageKnifeOption.signature,
requestSource requestSource
} }
// 启动线程下载和解码主图 // 启动线程下载和解码主图
@ -144,15 +144,15 @@ export class ImageKnifeDispatcher {
} }
} }
}); });
this.executingJobMap.remove(keyMemory) this.executingJobMap.remove(memoryKey)
} }
else { else {
LogUtil.log("error: no requestlist need to draw for key = " + keyMemory) LogUtil.log("error: no requestlist need to draw for key = " + memoryKey)
} }
} }
// 保存文件缓存 // 保存文件缓存
if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) { if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
ImageKnife.getInstance().saveWithoutWriteFile(keyFile, requestJobResult.bufferSize) ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize)
} }
let ImageKnifeData: ImageKnifeData = { let ImageKnifeData: ImageKnifeData = {
@ -164,7 +164,7 @@ export class ImageKnifeDispatcher {
// 保存内存缓存 // 保存内存缓存
if(currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) { if(currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) {
ImageKnife.getInstance() ImageKnife.getInstance()
.saveMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.imageKnifeOption), .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption),
ImageKnifeData) ImageKnifeData)
} }
if (requestList !== undefined) { if (requestList !== undefined) {
@ -190,11 +190,11 @@ export class ImageKnifeDispatcher {
}); });
this.executingJobMap.remove(keyMemory) this.executingJobMap.remove(memoryKey)
this.dispatchNextJob() this.dispatchNextJob()
} }
else { else {
LogUtil.log("error: no requestlist need to draw for key = " + keyMemory) LogUtil.log("error: no requestlist need to draw for key = " + memoryKey)
} }
// }) // })
@ -215,7 +215,7 @@ export class ImageKnifeDispatcher {
} }
setEngineKeyImpl(impl: IEngineKey): void { setEngineKeyImpl(impl: IEngineKey): void {
this.engineKeyImpl = impl; this.engineKey = impl;
} }
} }
@ -235,10 +235,13 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
totalSize: number = 2000 totalSize: number = 2000
} }
// 生成文件key
let fileKey = request.engineKey.generateFileKey(request.src, request.signature)
// 判断自定义下载 // 判断自定义下载
if (request.customGetImage !== undefined && typeof request.src === 'string' && (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0)) { if (request.customGetImage !== undefined && typeof request.src === 'string' && (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0)) {
// 先从文件缓存获取 // 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, request.key) resBuf = FileCache.getFileCacheByFile(request.context, fileKey)
if (resBuf === undefined) { if (resBuf === undefined) {
LogUtil.log("customGetImage customGetImage"); LogUtil.log("customGetImage customGetImage");
resBuf = await request.customGetImage(request.context, request.src) resBuf = await request.customGetImage(request.context, request.src)
@ -246,7 +249,7 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
if (resBuf !== undefined) { if (resBuf !== undefined) {
let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength
bufferSize = copyBuf.byteLength bufferSize = copyBuf.byteLength
FileCache.saveFileCacheOnlyFile(request.context, request.key, resBuf) FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf)
} }
} }
} }
@ -254,13 +257,8 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
if (typeof request.src === 'string') { if (typeof request.src === 'string') {
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载 if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
// 先从文件缓存获取 // 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, request.key) resBuf = FileCache.getFileCacheByFile(request.context, fileKey)
if (resBuf === undefined && request.onlyRetrieveFromCache != true && request.requestSource == 0) { if (resBuf === undefined && request.onlyRetrieveFromCache != true && request.requestSource == 0) {
// // 模拟耗时验证
// let start = (new Date()).getTime();
// while ((new Date()).getTime() - start < 5000) {
// continue;
// }
let httpRequest = http.createHttp(); let httpRequest = http.createHttp();
let progress: number = 0 let progress: number = 0
const headerObj: Record<string,object> = {} const headerObj: Record<string,object> = {}
@ -309,11 +307,11 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
if (resBuf !== undefined && request.writeCacheStrategy !== WriteCacheStrategyType.Memory) { if (resBuf !== undefined && request.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength
bufferSize = copyBuf.byteLength bufferSize = copyBuf.byteLength
FileCache.saveFileCacheOnlyFile(request.context, request.key, resBuf) FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf)
} }
} }
else { else {
LogUtil.log("success get image from filecache for key = " + request.key); LogUtil.log("success get image from filecache for key = " + fileKey);
} }
} else { //从本地文件获取 } else { //从本地文件获取
let stat = fs.statSync(request.src); let stat = fs.statSync(request.src);
@ -346,7 +344,8 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf)) let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf))
return { return {
pixelMap: base64str, pixelMap: base64str,
bufferSize: bufferSize bufferSize: bufferSize,
fileKey: fileKey
}; };
} }
@ -369,7 +368,8 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
return { return {
pixelMap: resPixelmap, pixelMap: resPixelmap,
bufferSize: bufferSize bufferSize: bufferSize,
fileKey: fileKey
}; };
} }
@ -389,12 +389,12 @@ export interface ImageKnifeRequestWithSource {
interface RequestJobResult { interface RequestJobResult {
pixelMap: PixelMap | string | undefined pixelMap: PixelMap | string | undefined
bufferSize: number bufferSize: number
fileKey: string
} }
interface RequestJobRequest { interface RequestJobRequest {
context: common.UIAbilityContext, context: common.UIAbilityContext,
src: string | PixelMap | Resource, src: string | PixelMap | Resource,
key: string,
headers?:Array<HeaderOptions>, headers?:Array<HeaderOptions>,
allHeaders:Map<string,Object>, allHeaders:Map<string,Object>,
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>, customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>,
@ -402,4 +402,6 @@ interface RequestJobRequest {
requestSource:ImageKnifeRequestSource requestSource:ImageKnifeRequestSource
transformation?: PixelMapTransformation transformation?: PixelMapTransformation
writeCacheStrategy?: WriteCacheStrategyType writeCacheStrategy?: WriteCacheStrategyType
signature?: string
engineKey:IEngineKey
} }

View File

@ -14,7 +14,6 @@
*/ */
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { ObjectKey } from './model/ObjectKey';
import { WriteCacheStrategyType } from './model/ImageKnifeData'; import { WriteCacheStrategyType } from './model/ImageKnifeData';
import { PixelMapTransformation } from './transform/PixelMapTransformation'; import { PixelMapTransformation } from './transform/PixelMapTransformation';
@ -34,7 +33,7 @@ export class ImageKnifeOption {
headerOption?: Array<HeaderOptions>; headerOption?: Array<HeaderOptions>;
// 自定义缓存关键字 // 自定义缓存关键字
signature?: ObjectKey; signature?: string;
objectFit?: ImageFit objectFit?: ImageFit

View File

@ -12,48 +12,36 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import util from '@ohos.util';
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'; import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
import { ImageKnifeOption } from '../ImageKnifeOption'; import { ImageKnifeOption } from '../ImageKnifeOption';
import { IEngineKey } from './IEngineKey'; import { IEngineKey } from './IEngineKey';
import { ObjectKey } from '../model/ObjectKey';
import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { PixelMapTransformation } from '../transform/PixelMapTransformation';
import { ImageKnifeRequestSource } from '../ImageKnifeDispatcher';
@Sendable
export class DefaultEngineKey implements IEngineKey { export class DefaultEngineKey implements IEngineKey {
private memoryKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
private fileKeyCache: util.LRUCache<string, string> = new util.LRUCache(1024)
// 生成内存缓存key // 生成内存缓存key
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string { generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";" imageKnifeOption: ImageKnifeOption, width?: number, height?: number): string {
if (imageKnifeOption.signature) { let key = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
src += "signature=" + imageKnifeOption.signature.getKey() + ";" if (requestSource === ImageKnifeRequestSource.SRC) {
if (imageKnifeOption.signature !== undefined && imageKnifeOption.signature !== "") {
key += "signature=" + imageKnifeOption.signature + ";"
}
if (imageKnifeOption.transformation) {
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
}
} }
if (imageKnifeOption.transformation) { return key
src += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
}
return this.generateKey(src, this.memoryKeyCache)
} }
// 生成文件缓存key // 生成文件缓存key
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string { generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string): string {
let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";" let src = "loadSrc=" + (typeof loadSrc == "string" ? loadSrc : JSON.stringify(loadSrc)) + ";"
if (signature) { if (signature !== undefined && signature !== "") {
src += "signature=" + signature.getKey() + ";" src += "signature=" + signature + ";"
}
return this.generateKey(src, this.fileKeyCache)
}
// key缓存策略避免无意义的 JSON.stringify
private generateKey(keyCache: string, cache: util.LRUCache<string, string>): string {
let result = cache.get(keyCache)
if (result != undefined) {
return result
} else {
result = SparkMD5.hashBinary(keyCache)
cache.put(keyCache, result)
return result
} }
return SparkMD5.hashBinary(src)
} }
private getTransformation(transformation: PixelMapTransformation): string { private getTransformation(transformation: PixelMapTransformation): string {

View File

@ -12,15 +12,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeRequestSource } from '../ImageKnifeDispatcher'
import { ImageKnifeOption } from '../ImageKnifeOption' import { ImageKnifeOption } from '../ImageKnifeOption'
import { ObjectKey } from '../model/ObjectKey'
export interface IEngineKey { export interface IEngineKey {
// 生成内存缓存key // 生成内存缓存key
generateMemoryKey(loadSrc: string | PixelMap | Resource, imageKnifeOption: ImageKnifeOption): string generateMemoryKey(loadSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,
imageKnifeOption: ImageKnifeOption, width?: number, height?: number): string
// 生成文件缓存key // 生成文件缓存key
generateFileKey(loadSrc: string | PixelMap | Resource, signature?: ObjectKey | undefined): string generateFileKey(loadSrc: string | PixelMap | Resource, signature?: string): string
} }

View File

@ -1,28 +0,0 @@
/*
* 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.
*/
export class ObjectKey{
private objectKey: string;
constructor(objectKey: string) {
this.objectKey = objectKey;
}
getKey(): string{
return this.objectKey;
}
}

View File

@ -31,7 +31,7 @@ export class FileCache {
maxSize: number = 0 maxSize: number = 0
path: string = "" path: string = ""
private lruCache: util.LRUCache<string, number> private lruCache: util.LRUCache<string, number>
static isInited: boolean = false private isInited: boolean = false
private context?: Context private context?: Context
readonly defaultMaxSize: number = 512; readonly defaultMaxSize: number = 512;
readonly defaultSize: number = 128; readonly defaultSize: number = 128;
@ -57,7 +57,7 @@ export class FileCache {
* 遍历缓存文件目录,初始化缓存 * 遍历缓存文件目录,初始化缓存
*/ */
public async initFileCache() { public async initFileCache() {
if (FileCache.isInited) { if (this.isInited) {
return return
} }
@ -100,7 +100,7 @@ export class FileCache {
} }
this.trimToSize(); this.trimToSize();
FileCache.isInited = true this.isInited = true
} }
// 添加缓存键值对,同时写文件 // 添加缓存键值对,同时写文件
@ -108,7 +108,7 @@ export class FileCache {
if (key == null || value == null) { if (key == null || value == null) {
throw new Error('key or value is invalid '); throw new Error('key or value is invalid ');
} }
if (!FileCache.isInited) { if (!this.isInited) {
return return
} }
@ -132,7 +132,7 @@ export class FileCache {
if (key == null || value == null) { if (key == null || value == null) {
throw new Error('key or value is invalid '); throw new Error('key or value is invalid ');
} }
if (!FileCache.isInited) { if (!this.isInited) {
return return
} }
@ -151,7 +151,7 @@ export class FileCache {
} }
get(key: string): ArrayBuffer | undefined { get(key: string): ArrayBuffer | undefined {
if (!FileCache.isInited) { if (!this.isInited) {
return return
} }
@ -167,7 +167,7 @@ export class FileCache {
if (key == null) { if (key == null) {
throw new Error('key is null,checking the parameter'); throw new Error('key is null,checking the parameter');
} }
if (!FileCache.isInited) { if (!this.isInited) {
return return
} }
@ -179,10 +179,10 @@ export class FileCache {
} }
async removeAll(): Promise<void> { async removeAll(): Promise<void> {
if (!FileCache.isInited) { if (!this.isInited) {
return return
} }
FileCache.isInited = false this.isInited = false
this.lruCache.clear() this.lruCache.clear()
this.currentMemory = 0; this.currentMemory = 0;
@ -191,7 +191,7 @@ export class FileCache {
await FileUtils.getInstance().deleteFile(this.path + filenames[i]) await FileUtils.getInstance().deleteFile(this.path + filenames[i])
} }
FileCache.isInited = true this.isInited = true
} }
size(): number { size(): number {
@ -242,9 +242,6 @@ export class FileCache {
* @param value * @param value
*/ */
static saveFileCacheOnlyFile(context: Context, key: string, value: ArrayBuffer): boolean { static saveFileCacheOnlyFile(context: Context, key: string, value: ArrayBuffer): boolean {
if (!FileCache.isInited) {
return false
}
// 写文件 // 写文件
FileUtils.getInstance() FileUtils.getInstance()
.writeFileSync(context.cacheDir + FileUtils.SEPARATOR + FileCache.CACHE_FOLDER + FileUtils.SEPARATOR + key, value) .writeFileSync(context.cacheDir + FileUtils.SEPARATOR + FileCache.CACHE_FOLDER + FileUtils.SEPARATOR + key, value)