ImageKnife提供清理缓存能力

Signed-off-by: 任伟x <renwei79@h-partners.com>
This commit is contained in:
任伟x 2024-05-22 17:28:30 +08:00
parent 3ecc586559
commit ee6e0acef6
11 changed files with 402 additions and 2 deletions

View File

@ -3,6 +3,7 @@
- 提供图片加载成功/失败的事件 - 提供图片加载成功/失败的事件
- 修复懒加载在多次点击出现卡死的问题 - 修复懒加载在多次点击出现卡死的问题
- 支持多种组合变换 - 支持多种组合变换
- 提供清理缓存能力
## 2.2.0-rc.2 ## 2.2.0-rc.2
- ImageKnife支持下采样 - ImageKnife支持下采样

View File

@ -381,6 +381,12 @@ request.skipMemoryCache(true)
| resumeRequests() | | 全局恢复暂停 | | resumeRequests() | | 全局恢复暂停 |
| isUrlExist(url, cacheType, size) | url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size可选 | | isUrlExist(url, cacheType, size) | url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size可选 |
| setMaxRequests(count: number) | count | 设置请求的最大并发数量 | | setMaxRequests(count: number) | count | 设置请求的最大并发数量 |
| removeAllMemoryCache() | | 清除全部内存缓存 |
| removeAllFileCache() | | 清除全部磁盘缓存 |
| removeMemoryCache(url: string) | url: string | 清除指定内存缓存 |
| removeFileCache(url: string) | url: string | 清除指定磁盘缓存 |
| getMemoryCacheKey(url: string) | url: string | 获取指定图片内存缓存key |
| getDiskCacheKey(url: string) | url: string | 获取指定图片磁盘缓存key |
### 缓存策略相关 ### 缓存策略相关

View File

@ -438,6 +438,14 @@ struct IndexFunctionDemo {
router.pushUrl({ url: 'pages/testImageKnifeLoadState' }); router.pushUrl({ url: 'pages/testImageKnifeLoadState' });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试内存删除').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试内存删除')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeRemoveCache' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
} }
} }
.width('100%') .width('100%')

View File

@ -0,0 +1,269 @@
/*
* Copyright (C) 2024 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 {
ImageKnifeComponent,
ImageKnifeOption,
ImageKnifeGlobal,
ImageKnife,
ImageKnifeData,
Size,
CacheType
} from '@ohos/libraryimageknife'
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base';
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
@Entry
@Component
struct testImageKnifeRemoveCache {
@State url: string = '';
@State urlGif: string = 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658';
@State urlPng: string = 'https://img-blog.csdnimg.cn/20191215043500229.png';
@State urlJpg: string = 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB';
@State urlBmp: string = 'https://img-blog.csdn.net/20140514114029140';
@State urlWebp: string = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp';
@State imagePixelMap: PixelMap | undefined = undefined;
@State imagePixelMap_: PixelMap | undefined = undefined;
private index_: number = -1;
private tempSize: number = 200;
private timeId = -1;
private comSize: Size = {
width: this.tempSize,
height: this.tempSize,
}
@State imageKnifeOption: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
};
loadSuccess = (data: ImageKnifeData) => {
clearTimeout(this.timeId);
if (data.isPixelMap()) {
if (data.drawPixelMap) {
let pixelmap = data.drawPixelMap.imagePixelMap;
if (pixelmap) {
if (this.index_ == 1) {
this.imagePixelMap = pixelmap;
} else if (this.index_ == 2) {
this.imagePixelMap_ = pixelmap;
}
}
}
}
if (data.isGIFFrame()) {
let index: number = 0
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let renderGif = () => {
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let pixelmap = data.drawGIFFrame.imageGIFFrames[index].drawPixelMap;
let delay = data.drawGIFFrame.imageGIFFrames[index].delay;
if (pixelmap) {
if (this.index_ == 1) {
this.imagePixelMap = pixelmap;
} else if (this.index_ == 2) {
this.imagePixelMap_ = pixelmap;
}
}
index++;
if (index == data.drawGIFFrame.imageGIFFrames.length - 1) {
index = 0;
}
this.timeId = setTimeout(renderGif, data!.drawGIFFrame!.imageGIFFrames![index].delay);
}
}
}
renderGif();
}
}
}
}
loadError = (err: BusinessError) => {
}
build() {
Scroll() {
Column() {
Text('图片内存和磁盘缓存删除').fontSize(30);
Text('测试删除缓存时候关闭掉网络').fontSize(15);
Row() {
Button('png')
.margin({right:10})
.onClick(() => {
this.index_ = 0;
this.url = this.urlPng;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('bmp')
.margin({right:10})
.onClick(() => {
this.index_ = 0;
this.url = this.urlBmp;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('webp')
.margin({right:10})
.onClick(() => {
this.index_ = 0;
this.url = this.urlWebp;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('jpg')
.margin({right:10})
.onClick(() => {
this.index_ = 0;
this.url = this.urlJpg;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('gif')
.margin({right:10})
.onClick(() => {
this.index_ = 0;
this.url = this.urlGif;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
}.margin({top: 20})
Row() {
Button('缓存图片')
.margin({right:10})
.onClick(() => {
this.index_ = 1;
imageKnife?.isUrlExist(this.url, CacheType.Cache, this.comSize).then(this.loadSuccess)
.catch(this.loadError);
})
Button('磁盘图片')
.margin({right:10})
.onClick(() => {
this.index_ = 2;
imageKnife?.isUrlExist(this.url, CacheType.Disk, this.comSize).then(this.loadSuccess)
.catch(this.loadError);
})
}.margin({top: 20})
Row() {
Button('清除全部缓存')
.onClick(() => {
imageKnife?.removeAllMemoryCache();
imageKnife?.removeAllFileCache();
})
Button('清除全部内存缓存')
.onClick(() => {
imageKnife?.removeAllMemoryCache();
})
Button('清除全部磁盘缓存')
.onClick(() => {
imageKnife?.removeAllFileCache();
})
}.margin({top: 20})
Row() {
Button('清除指定内存缓存')
.margin({right:10})
.onClick(() => {
imageKnife?.removeMemoryCache(this.url);
})
Button('清除指定磁盘缓存')
.margin({right:10})
.onClick(() => {
imageKnife?.removeFileCache(this.url);
})
}.margin({top: 20})
Text('网络图').fontSize(15);
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('缓存图').fontSize(15);
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.imagePixelMap as image.PixelMap
}
})
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('磁盘图').fontSize(15);
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.imagePixelMap_ as image.PixelMap
}
})
.width(200)
.height(200)
.backgroundColor(Color.Orange)
}
.alignItems(HorizontalAlign.Center)
.width('100%')
}
.width('100%')
.height('100%')
}
aboutToAppear() {
}
aboutToDisappear() {
}
onBackPress() {
}
}

View File

@ -60,6 +60,7 @@
"pages/testCustomDataFetchClientWithPage", "pages/testCustomDataFetchClientWithPage",
"pages/testReuseAblePages", "pages/testReuseAblePages",
"pages/downsamplingPage", "pages/downsamplingPage",
"pages/testImageKnifeLoadState" "pages/testImageKnifeLoadState",
"pages/testImageKnifeRemoveCache"
] ]
} }

View File

@ -14,7 +14,9 @@
*/ */
import hilog from '@ohos.hilog'; import hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
import {ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal} from '@ohos/imageknife' import { DiskLruCache, ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal,LruCache} from '@ohos/imageknife';
import { common } from '@kit.AbilityKit';
import { GlobalContext } from '../testability/GlobalContext';
const BASE_COUNT: number = 2000; const BASE_COUNT: number = 2000;
@ -74,6 +76,33 @@ export default function ImageKnifeTest() {
} }
}) })
it('TestRemoveAllMemoryCache',2,()=>{
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
imageKnife?.removeAllMemoryCache();
let a = imageKnife?.getMemoryCache();
expect(a).assertEqual(undefined);
})
it('TestRemoveAllFileCache',3,()=>{
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife();
imageKnife?.removeAllFileCache();
let a = imageKnife?.getDiskMemoryCache();
expect(a).assertEqual(undefined);
})
it('TestRemoveMemoryCache',4,()=>{
let memoryCache = new LruCache<string, string>(5);
memoryCache.put("1","1");
memoryCache.remove("1");
let result = memoryCache.get("1");
expect(result).assertEqual(undefined);
})
it('TestRemoveFileCache',5,()=>{
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let disLruCache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
disLruCache.set('test', "Hello World Simple Example.");
disLruCache.deleteCacheDataByKey('test');
let a = disLruCache.get('test');
expect(a).assertEqual(undefined);
})
}) })
} }

View File

@ -272,6 +272,14 @@ export class DiskLruCache {
this.cacheMap.clear() this.cacheMap.clear()
this.size = 0 this.size = 0
} }
async cleanAllDiskCache() {
let filenames: string[] = await FileUtils.getInstance().ListFile(this.path);
for (let i = 0; i < filenames.length; i++) {
await FileUtils.getInstance().deleteFile(this.path + filenames[i]);
}
this.cacheMap.clear();
this.size = 0;
}
getCacheMap() { getCacheMap() {
return this.cacheMap; return this.cacheMap;

View File

@ -410,5 +410,13 @@ export class FileUtils {
fs.readSync(fd, buf) fs.readSync(fd, buf)
return buf return buf
} }
async ListFile(path: string): Promise<string[]> {
try {
return fs.listFile(path);
} catch (err) {
console.error("FileUtils ListFile failed with error message: " + err.message + ", error code: " + err.code);
}
return [];
}
} }

View File

@ -49,6 +49,13 @@ export class LruCache<K, V> {
} }
return preValue return preValue
} }
removeAll() {
this.map.each((value, key) => {
this.remove(key);
})
this.map.clear();
this.size = 0;
}
// 获取键为key的value // 获取键为key的value
get(key: K): V | undefined { get(key: K): V | undefined {

View File

@ -171,6 +171,66 @@ export class ImageKnife {
setMemoryCache(lrucache: MemoryLruCache) { setMemoryCache(lrucache: MemoryLruCache) {
this.memoryCache = lrucache; this.memoryCache = lrucache;
} }
// 移除全部内存缓存
removeAllMemoryCache(): void {
this.memoryCacheProxy.removeAllValue();
}
// 移除全部磁盘缓存
async removeAllFileCache(): Promise<void> {
if (this.diskMemoryCache !== undefined) {
await this.getDiskMemoryCache().cleanAllDiskCache();
}
}
// 移除指定内存缓存
removeMemoryCache(url: string): void {
let key = this.getMemoryCacheKey(url);
this.memoryCacheProxy.removeValue(key);
}
// 移除指定磁盘缓存
removeFileCache(url: string): void {
let key = this.getDiskCacheKey(url);
this.diskMemoryCache.deleteCacheDataByKey(key);
}
// 获取指定内存缓存key值
getMemoryCacheKey(url: string) {
let request = new RequestOption();
let factories: EngineKeyInterface;
let dontAnimateFlag = request.dontAnimateFlag;
let signature = request.signature;
const imageSize: Size = {
width: 200,
height: 200,
}
let size = JSON.stringify(imageSize);
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
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() + ",";
}
}
}
return factories.generateMemoryCacheKey(url, size, transformed, dontAnimateFlag, signature);
}
// 获取指定磁盘缓存key值
getDiskCacheKey(url: string) {
let request = new RequestOption();
let signature = request.signature;
let factories: EngineKeyInterface;
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
return factories.generateOriginalDiskCacheKey(url, signature);
}
getDefaultListener() { getDefaultListener() {
return this.defaultListener; return this.defaultListener;

View File

@ -39,6 +39,9 @@ export class MemoryCacheProxy <K, V> implements ICache<K, V> {
removeValue(key: K): V|undefined{ removeValue(key: K): V|undefined{
return this.mLruCache.remove(key); return this.mLruCache.remove(key);
} }
removeAllValue() {
this.mLruCache.removeAll();
}
clear() { clear() {
this.mLruCache.evicAll(); this.mLruCache.evicAll();