1.修改imageknifeOpion为小写

2.writeCacheStrategy为memory时,子线程不写文件
3.文件缓存未初始化时,不写缓存

Signed-off-by: madixin <madixin@huawei.com>
This commit is contained in:
madixin 2024-05-03 15:06:58 +08:00
parent 00f5e81571
commit 33ba458600
7 changed files with 53 additions and 52 deletions

View File

@ -6,7 +6,7 @@
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本
- 支持自定义内存缓存策略,支持设置内存缓存的大小。
- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)
- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。
- 支持自定义实现图片获取/网络下载
- 支持监听网络下载回调进度
@ -42,6 +42,9 @@
## 下载安装
```
ohpm install @ohos/imageknife
// 如果需要用文件缓存,需要提前初始化文件缓存
await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
```
## 使用说明
@ -162,7 +165,7 @@ ImageKnifeComponent({ ImageKnifeOption:
| addHeader | key: string, value: Object | 全局添加http请求头 |
| setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 |
| deleteHeader | key: string | 全局删除http请求头 |
| setEngineKeyImpl | CustomEngineKeyImpl | 全局配置缓存key |
| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 |
## 约束与限制
在下述版本验证通过:

View File

@ -25,12 +25,6 @@ struct ImageTransformation {
this.isBlur = value
this.upedateImageKnifeOption()
})
.mark({
strokeColor: Color.Black,
size: 50,
strokeWidth: 5
})
.unselectedColor(Color.Red)
.width(30)
.height(30)
Text('模糊效果').fontSize(20)

View File

@ -54,13 +54,13 @@ export default function DefaultJobQueueTest() {
job.add(makeRequest("medium4", getContext() as common.UIAbilityContext))
expect(job.getQueueLength()).assertEqual(7)
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("high1")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("medium1")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("medium2")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("medium3")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("medium4")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("low1")
expect(job.pop()!.ImageKnifeOption.loadSrc).assertEqual("low2")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("high1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium2")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium3")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium4")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low2")
expect(job.pop()).assertEqual(undefined)
expect(job.getQueueLength()).assertEqual(0)

View File

@ -48,7 +48,7 @@ export class ImageKnifeDispatcher {
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): boolean {
let memoryCache: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, request.ImageKnifeOption))
.loadFromMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, request.imageKnifeOption))
if (memoryCache !== undefined) {
// 画主图
if (request.requestState === ImageKnifeRequestState.PROGRESS) {
@ -69,7 +69,7 @@ export class ImageKnifeDispatcher {
enqueue(request: ImageKnifeRequest): void {
//1.内存有的话直接渲染
if (this.showFromMemomry(request, request.ImageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)) {
if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)) {
return
}
@ -83,22 +83,22 @@ export class ImageKnifeDispatcher {
executeJob(request: ImageKnifeRequest): void {
// 加载占位符
if (request.ImageKnifeOption.placeholderSrc !== undefined) {
if (this.showFromMemomry(request, request.ImageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER) === false) {
this.getAndShowImage(request, request.ImageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
if (request.imageKnifeOption.placeholderSrc !== undefined) {
if (this.showFromMemomry(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER) === false) {
this.getAndShowImage(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
}
}
// 加载主图
this.getAndShowImage(request, request.ImageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)
this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC)
}
/**
* 获取和显示图片
*/
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource): void {
let keyMemory: string = this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.ImageKnifeOption)
let keyFile: string = this.engineKeyImpl.generateFileKey(imageSrc, currentRequest.ImageKnifeOption.signature)
let keyMemory: string = this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.imageKnifeOption)
let keyFile: string = this.engineKeyImpl.generateFileKey(imageSrc, currentRequest.imageKnifeOption.signature)
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(keyMemory)
if (requestList == undefined) {
requestList = new List()
@ -113,18 +113,19 @@ export class ImageKnifeDispatcher {
context: currentRequest.context,
src: imageSrc,
key: keyFile,
headers:currentRequest.ImageKnifeOption.headerOption,
headers:currentRequest.imageKnifeOption.headerOption,
allHeaders:currentRequest.headers,
customGetImage: currentRequest.ImageKnifeOption.customGetImage,
onlyRetrieveFromCache: currentRequest.ImageKnifeOption.onlyRetrieveFromCache,
transformation:currentRequest.ImageKnifeOption.transformation,
customGetImage: currentRequest.imageKnifeOption.customGetImage,
onlyRetrieveFromCache: currentRequest.imageKnifeOption.onlyRetrieveFromCache,
transformation:currentRequest.imageKnifeOption.transformation,
writeCacheStrategy: currentRequest.imageKnifeOption.writeCacheStrategy,
requestSource
}
// 启动线程下载和解码主图
let task = new taskpool.Task(requestJob, request)
// 监听网络回调事件
if (currentRequest.ImageKnifeOption.progressListener !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
let progressCallBack = currentRequest.ImageKnifeOption.progressListener
if (currentRequest.imageKnifeOption.progressListener !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
let progressCallBack = currentRequest.imageKnifeOption.progressListener
emitter.on(Constants.PROGRESS_EMITTER, (data) => {
progressCallBack(data?.data?.value as number)
});
@ -136,10 +137,10 @@ export class ImageKnifeDispatcher {
if (pixelmap === undefined) {
if (requestList !== undefined) {
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.source === ImageKnifeRequestSource.SRC && currentRequest.ImageKnifeOption.errorholderSrc !== undefined) {
if (requestWithSource.source === ImageKnifeRequestSource.SRC && currentRequest.imageKnifeOption.errorholderSrc !== undefined) {
if (this.showFromMemomry(currentRequest, currentRequest.ImageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER) === false) {
this.getAndShowImage(currentRequest, currentRequest.ImageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER)
if (this.showFromMemomry(currentRequest, currentRequest.imageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER) === false) {
this.getAndShowImage(currentRequest, currentRequest.imageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER)
}
}
});
@ -150,7 +151,7 @@ export class ImageKnifeDispatcher {
}
}
// 保存文件缓存
if (requestJobResult.bufferSize > 0 && currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
ImageKnife.getInstance().saveWithoutWriteFile(keyFile, requestJobResult.bufferSize)
}
@ -161,9 +162,9 @@ export class ImageKnifeDispatcher {
}
// 保存内存缓存
if(currentRequest.ImageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) {
if(currentRequest.imageKnifeOption.writeCacheStrategy !== WriteCacheStrategyType.File) {
ImageKnife.getInstance()
.saveMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.ImageKnifeOption),
.saveMemoryCache(this.engineKeyImpl.generateMemoryKey(imageSrc, currentRequest.imageKnifeOption),
ImageKnifeData)
}
if (requestList !== undefined) {
@ -305,7 +306,7 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
});
// 保存文件缓存
if (resBuf !== undefined) {
if (resBuf !== undefined && request.writeCacheStrategy !== WriteCacheStrategyType.Memory) {
let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength
bufferSize = copyBuf.byteLength
FileCache.saveFileCacheOnlyFile(request.context, request.key, resBuf)
@ -324,7 +325,6 @@ async function requestJob(request: RequestJobRequest): Promise<RequestJobResult
}
}
} else if ((request.src as Resource).id !== undefined) { //从资源文件获取
resBuf = FileCache.getFileCacheByFile(request.context, request.key)
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == 0) {
resBuf = request.context.resourceManager.getMediaContentSync((request.src as Resource).id).buffer as ArrayBuffer
} else if (resBuf == undefined && request.requestSource != 0) {
@ -401,4 +401,5 @@ interface RequestJobRequest {
onlyRetrieveFromCache?: boolean
requestSource:ImageKnifeRequestSource
transformation?: PixelMapTransformation
writeCacheStrategy?: WriteCacheStrategyType
}

View File

@ -25,7 +25,7 @@ export class ImageKnifeRequest {
requestState: ImageKnifeRequestState = ImageKnifeRequestState.PROGRESS
componentWidth: number = 0
componentHeight: number = 0
ImageKnifeOption: ImageKnifeOption
imageKnifeOption: ImageKnifeOption
context: common.UIAbilityContext
ImageKnifeRequestCallback: ImageKnifeRequestCallback
componentVersion: number = 0
@ -36,7 +36,7 @@ export class ImageKnifeRequest {
height: number,
version: number,
ImageKnifeRequestCallback: ImageKnifeRequestCallback) {
this.ImageKnifeOption = option
this.imageKnifeOption = option
this.context = uIAbilityContext
this.componentWidth = width
this.componentHeight = height

View File

@ -27,9 +27,9 @@ export class DefaultJobQueue implements IJobQueue {
}
add(request: ImageKnifeRequest): void {
if (request.ImageKnifeOption.priority === undefined || request.ImageKnifeOption.priority === taskpool.Priority.MEDIUM) {
if (request.imageKnifeOption.priority === undefined || request.imageKnifeOption.priority === taskpool.Priority.MEDIUM) {
this.normalQueue.add(request)
} else if (request.ImageKnifeOption.priority === taskpool.Priority.HIGH) {
} else if (request.imageKnifeOption.priority === taskpool.Priority.HIGH) {
this.highQueue.add(request)
} else {
this.lowQueue.add(request)

View File

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