forked from floraachy/ImageKnife
Merge branch 'master' of gitee.com:openharmony-tpc/ImageKnife into master
Signed-off-by: 任伟x <renwei79@h-partners.com>
This commit is contained in:
commit
68257fb666
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -1,7 +1,11 @@
|
|||
## 2.1.2-rc.13
|
||||
- 修改ImageKnife跳过网络,从内存中获取图片 cacheType参数未使用bug
|
||||
- 新增WEBP图片解析能力。
|
||||
- 新增gif图片支持暂停播放功能
|
||||
## 2.2.0-rc.1
|
||||
- 修改ImageKnife跳过网络,点击默认,图片没有传入宽高,无显示bug
|
||||
- ImageKnife支持根据自定义key获取已缓存的图片
|
||||
- ImageKnife加载图片支持自定义网络栈和图片加载组件
|
||||
- 适配复用场景触发懒加载onDataReloaded
|
||||
- ImageKnife控制重要图片请求加载优先级
|
||||
|
||||
## 2.2.0-rc.0
|
||||
- 修复自定义DataFetch接口实现不生效问题
|
||||
- 修改磁盘缓存到子线程
|
||||
- 更新SDK到API12
|
||||
|
@ -9,7 +13,11 @@
|
|||
- 修改全局请求头覆盖request请求头
|
||||
- imageKnife支持heic测试demo独立页面展示
|
||||
- drawLifeCycle支持gif图
|
||||
- ImageKnife支持根据自定义key获取已缓存的图片
|
||||
|
||||
## 2.1.2
|
||||
- 修改ImageKnife跳过网络,从内存中获取图片 cacheType参数未使用bug
|
||||
- 新增WEBP图片解析能力。
|
||||
- 新增gif图片支持暂停播放功能
|
||||
|
||||
## 2.1.2-rc.12
|
||||
- 新增gif播放次数功能
|
||||
|
|
22
README.md
22
README.md
|
@ -337,13 +337,14 @@ request.skipMemoryCache(true)
|
|||
|
||||
### ImageKnife 启动器/门面类
|
||||
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
| ------------------------------- | ---------------------- | ---------------------------------- |
|
||||
| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 |
|
||||
| preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 |
|
||||
| pauseRequests() | | 全局暂停请求 |
|
||||
| resumeRequests() | | 全局恢复暂停 |
|
||||
| isUrlExist(url, cacheType, size)| url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size(可选)|
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
|----------------------------------| ---------------------- | ------------------------------------------------------------ |
|
||||
| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 |
|
||||
| preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 |
|
||||
| pauseRequests() | | 全局暂停请求 |
|
||||
| resumeRequests() | | 全局恢复暂停 |
|
||||
| isUrlExist(url, cacheType, size) | url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size(可选) |
|
||||
| setMaxRequests(count: number) | count | 设置请求的最大并发数量 |
|
||||
|
||||
### 缓存策略相关
|
||||
|
||||
|
@ -448,6 +449,13 @@ export default class EntryAbility extends UIAbility {
|
|||
}
|
||||
```
|
||||
|
||||
### Queue
|
||||
|
||||
| 方法名 | 入参 | 接口描述 |
|
||||
| ----------------------------------- | ----------------------- | ------------------------------ |
|
||||
| getQueueLength(): number | | 获取队列总长度 |
|
||||
| add(request: RequestOption) | request:RequestOption | 在队列尾部插入元素 |
|
||||
| pop(): RequestOption | undefined | | 删除队列头元素并返回该删除元素 |
|
||||
|
||||
## 约束与限制
|
||||
|
||||
|
|
|
@ -127,6 +127,11 @@ struct IndexFunctionDemo {
|
|||
console.log("测试一级内存缓存")
|
||||
router.pushUrl({ url: "pages/testReusePhotoPage" });
|
||||
}).margin({ top: 5, left: 3 })
|
||||
Button("适配复用场景")
|
||||
.onClick(() => {
|
||||
console.log("测试一级内存缓存")
|
||||
router.pushUrl({ url: "pages/testReuseAblePages" });
|
||||
}).margin({ top: 5, left: 3 })
|
||||
}.width('100%')
|
||||
.height(60).backgroundColor(Color.Pink)
|
||||
Text("测试占位图 失败占位图 功能点").fontSize(15)
|
||||
|
@ -404,6 +409,14 @@ struct IndexFunctionDemo {
|
|||
router.pushUrl({ url: 'pages/testImageKnifeNetPlaceholder' });
|
||||
}).margin({ top: 5, left: 3 })
|
||||
}.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/testCustomDataFetchClientWithPage' });
|
||||
}).margin({ top: 5, left: 3 })
|
||||
}.width('100%').height(60).backgroundColor(Color.Pink)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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 {
|
||||
CustomDataFetchClient,
|
||||
DataFetchResult,
|
||||
DownloadClient,
|
||||
ImageKnifeComponent,
|
||||
ImageKnifeGlobal,
|
||||
ImageKnifeOption,
|
||||
LogUtil,
|
||||
ScaleType
|
||||
} from '@ohos/libraryimageknife';
|
||||
|
||||
import http from '@ohos.net.http';
|
||||
|
||||
class CommonDataSource <T> implements IDataSource {
|
||||
private dataArray: T[] = []
|
||||
private listeners: DataChangeListener[] = []
|
||||
|
||||
constructor(element: []) {
|
||||
this.dataArray = element
|
||||
}
|
||||
|
||||
public getData(index: number) {
|
||||
return this.dataArray[index]
|
||||
}
|
||||
|
||||
public totalCount(): number {
|
||||
return this.dataArray.length
|
||||
}
|
||||
|
||||
public addData(index: number, data: T[]): void {
|
||||
this.dataArray = this.dataArray.concat(data)
|
||||
this.notifyDataAdd(index)
|
||||
}
|
||||
|
||||
unregisterDataChangeListener(listener: DataChangeListener): void {
|
||||
const pos = this.listeners.indexOf(listener);
|
||||
if (pos >= 0) {
|
||||
this.listeners.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
registerDataChangeListener(listener: DataChangeListener): void {
|
||||
if (this.listeners.indexOf(listener) < 0) {
|
||||
this.listeners.push(listener)
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataAdd(index: number): void {
|
||||
this.listeners.forEach((listener: DataChangeListener) => {
|
||||
listener.onDataAdd(index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestCustomDataFetchClientWithPage {
|
||||
@State hotCommendList: CommonDataSource<string> = new CommonDataSource<string>([])
|
||||
@State singleImageKnifeOption: ImageKnifeOption =
|
||||
{
|
||||
loadSrc: $r('app.media.icon'),
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
};
|
||||
@State isSingleImageVisible: boolean = true;
|
||||
@State isAllImageVisible: boolean = false;
|
||||
@State isCustom: boolean = false;
|
||||
private data: Array<string> = [
|
||||
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg"
|
||||
]
|
||||
private addData: Array<string> = [
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg"
|
||||
|
||||
]
|
||||
private cancelData: Array<string> = [
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg"
|
||||
]
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data)
|
||||
LogUtil.log('TestCustomDataFetch about to appear.')
|
||||
}
|
||||
|
||||
build() {
|
||||
Scroll() {
|
||||
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
|
||||
|
||||
Button("单个图片").margin(16).onClick(() => {
|
||||
LogUtil.log('TestCustomDataFetch click single.');
|
||||
this.isSingleImageVisible = true;
|
||||
this.isAllImageVisible = false;
|
||||
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient());
|
||||
|
||||
this.singleImageKnifeOption = {
|
||||
loadSrc: 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg',
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
customGetImage: custom
|
||||
}
|
||||
})
|
||||
Button("全部图片").margin(16).onClick(() => {
|
||||
LogUtil.log('TestCustomDataFetch click all.');
|
||||
this.isSingleImageVisible = false;
|
||||
this.isAllImageVisible = true;
|
||||
|
||||
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient());
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.addData)
|
||||
|
||||
})
|
||||
|
||||
Button("取消自定义全部图片").margin(16).onClick(() => {
|
||||
LogUtil.log('TestCustomDataFetch click cancel.');
|
||||
this.isSingleImageVisible = false;
|
||||
this.isAllImageVisible = true;
|
||||
|
||||
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new DownloadClient());
|
||||
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.cancelData)
|
||||
})
|
||||
}
|
||||
|
||||
// 单个图片使用自定义网络栈
|
||||
ImageKnifeComponent({ imageKnifeOption: this.singleImageKnifeOption })
|
||||
.width(200)
|
||||
.height(200)
|
||||
.margin({ top: 50 })
|
||||
.visibility(this.isSingleImageVisible ? Visibility.Visible : Visibility.None)
|
||||
|
||||
// 全部图片使用自定义网络栈
|
||||
Column() {
|
||||
Grid() {
|
||||
LazyForEach(this.hotCommendList, (item: string) => {
|
||||
GridItem() {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item,
|
||||
placeholderSrc: $r('app.media.icon'),
|
||||
errorholderSrc: $r('app.media.icon_failed'),
|
||||
placeholderScaleType: ScaleType.CENTER_CROP,
|
||||
mainScaleType: ScaleType.CENTER_CROP,
|
||||
}
|
||||
}).width('100%').height('100%')
|
||||
}.width('40%').height(200)
|
||||
}, (item: string) => JSON.stringify(item))
|
||||
}
|
||||
.columnsTemplate('1fr 1fr')
|
||||
.columnsGap(8)
|
||||
.rowsGap(10)
|
||||
.width('100%')
|
||||
.hitTestBehavior(HitTestMode.None)
|
||||
.maxCount(10)
|
||||
}.margin({ top: 5 })
|
||||
.visibility(this.isAllImageVisible ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
|
||||
@Concurrent
|
||||
async function custom(context: Context, loadSrc: string): Promise<DataFetchResult> {
|
||||
let result: DataFetchResult = new DataFetchResult();
|
||||
try {
|
||||
let arrayBuffers = new Array<ArrayBuffer>();
|
||||
let httpRequest = http.createHttp()
|
||||
httpRequest.on('headersReceive', (header: Object) => {
|
||||
// 跟服务器连接成功准备下载
|
||||
})
|
||||
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
|
||||
// 下载数据流多次返回
|
||||
arrayBuffers.push(data);
|
||||
})
|
||||
httpRequest.on('dataEnd', () => {
|
||||
// 下载完毕
|
||||
})
|
||||
|
||||
const resultCode = await httpRequest.requestInStream(loadSrc as string,
|
||||
{
|
||||
method: http.RequestMethod.GET,
|
||||
expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
||||
connectTimeout: 60000, // 可选 默认60000ms
|
||||
readTimeout: 0, // 可选, 默认为60000ms
|
||||
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
|
||||
usingCache: false
|
||||
}).catch((err: Error) => {
|
||||
result.error = 'TestCustomDataFetchClientWithPage requestInStream error.' + JSON.stringify(err);
|
||||
})
|
||||
if (resultCode == 200) {
|
||||
//let combineArray = this.combineArrayBuffers(arrayBuffers);
|
||||
// 计算多个ArrayBuffer的总字节大小
|
||||
let totalByteLength = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
totalByteLength += arrayBuffer.byteLength;
|
||||
}
|
||||
// 创建一个新的ArrayBuffer
|
||||
const combinedArrayBuffer = new ArrayBuffer(totalByteLength);
|
||||
|
||||
// 创建一个Uint8Array来操作新的ArrayBuffer
|
||||
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
|
||||
|
||||
// 依次复制每个ArrayBuffer的内容到新的ArrayBuffer中
|
||||
let offset = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
const sourceUint8Array = new Uint8Array(arrayBuffer);
|
||||
combinedUint8Array.set(sourceUint8Array, offset);
|
||||
offset += sourceUint8Array.length;
|
||||
}
|
||||
result.data = combinedArrayBuffer;
|
||||
} else {
|
||||
result.error = 'TestCustomDataFetchClientWithPage error. resultCode = ' + resultCode;
|
||||
}
|
||||
console.log('TestCustomDataFetch single onComplete, code = ' + resultCode + ',length = ' + result.data?.byteLength);
|
||||
} catch (error) {
|
||||
result.error = 'TestCustomDataFetchClientWithPage error' + error.stack;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ struct testImageKnifeCache {
|
|||
Button('默认')
|
||||
.onClick(() => {
|
||||
this.index_ = 2;
|
||||
imageKnife?.isUrlExist(this.url).then(this.loadSuccess)
|
||||
imageKnife?.isUrlExist(this.url, CacheType.Default, this.comSize).then(this.loadSuccess)
|
||||
.catch(this.loadError);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,83 +12,177 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ImageKnifeComponent , Priority , NONE } from '@ohos/libraryimageknife'
|
||||
import { ImageKnifeComponent, ImageKnifeOption, Priority, NONE, ImageKnifeGlobal } from '@ohos/libraryimageknife';
|
||||
const dataBak: ImageKnifeOption[] = [
|
||||
{
|
||||
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "https://img-blog.csdn.net/20140514114029140",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc:"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
priority: Priority.LOW
|
||||
}
|
||||
];
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestPriorityComponent {
|
||||
private data: string[] = [
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
|
||||
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
|
||||
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
|
||||
'https://img-blog.csdnimg.cn/20191215043500229.png',
|
||||
'https://img-blog.csdn.net/20140514114029140',
|
||||
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
|
||||
]
|
||||
@State data: ImageKnifeOption[] = [
|
||||
{
|
||||
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
|
||||
priority: Priority.HIGH
|
||||
},
|
||||
{
|
||||
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
priority: Priority.MEDIUM
|
||||
},
|
||||
{
|
||||
loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "https://img-blog.csdn.net/20140514114029140",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp",
|
||||
priority: Priority.LOW
|
||||
},
|
||||
{
|
||||
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
priority: Priority.LOW
|
||||
}
|
||||
];
|
||||
@State maxRequests: number | undefined = ImageKnifeGlobal?.getInstance()?.getImageKnife()?.maxRequests;
|
||||
|
||||
build(){
|
||||
Column(){
|
||||
Grid(){
|
||||
ForEach(this.data,(item:string,index:number)=>{
|
||||
GridItem(){
|
||||
if(index % 2 == 0){
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:item,
|
||||
placeholderSrc:$r('app.media.icon_loading'),
|
||||
strategy:new NONE(),
|
||||
isCacheable:false,
|
||||
priority:Priority.LOW
|
||||
}
|
||||
})
|
||||
} else if (index % 3 == 0) {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:item,
|
||||
placeholderSrc:$r('app.media.icon_loading'),
|
||||
strategy:new NONE(),
|
||||
isCacheable:false,
|
||||
priority:Priority.MEDIUM
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:{
|
||||
loadSrc:item,
|
||||
placeholderSrc:$r('app.media.icon_loading'),
|
||||
strategy:new NONE(),
|
||||
isCacheable:false,
|
||||
priority:Priority.HIGH
|
||||
}
|
||||
})
|
||||
build() {
|
||||
Scroll() {
|
||||
Column() {
|
||||
Text('最大并发数: ' + this.maxRequests).width('50%').height(30)
|
||||
Button('修改最大并发数为1').width('50%').height(30)
|
||||
.onClick(() => {
|
||||
if (ImageKnifeGlobal?.getInstance()?.getImageKnife()) {
|
||||
ImageKnifeGlobal?.getInstance()?.getImageKnife()?.setMaxRequests(1);
|
||||
this.maxRequests = ImageKnifeGlobal?.getInstance()?.getImageKnife()?.maxRequests;
|
||||
this.data = [...dataBak, ...dataBak, ...dataBak];
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
Grid() {
|
||||
ForEach(this.data, (item: ImageKnifeOption, index: number) => {
|
||||
GridItem() {
|
||||
Flex() {
|
||||
Text(item?.priority?.toString() || '')
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: item.loadSrc,
|
||||
placeholderSrc: $r('app.media.icon_loading'),
|
||||
strategy: new NONE(),
|
||||
isCacheable: false,
|
||||
priority: item.priority
|
||||
}
|
||||
})
|
||||
}.height(60)
|
||||
}
|
||||
})
|
||||
}
|
||||
.width("100%")
|
||||
.height("100%")
|
||||
.columnsTemplate("1fr 1fr 1fr 1fr 1fr")
|
||||
.columnsGap(10)
|
||||
.rowsGap(10)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
.maxCount(10)
|
||||
}
|
||||
.width("100%")
|
||||
.height("100%")
|
||||
.columnsTemplate("1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr")
|
||||
.rowsTemplate("1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr")
|
||||
.columnsGap(10)
|
||||
.backgroundColor(0xFAEEE0)
|
||||
}.width("100%").height("100%").backgroundColor(Color.Pink)
|
||||
.backgroundColor(Color.Pink)
|
||||
.margin({ top: 5 })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* 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 } from '@ohos/libraryimageknife'
|
||||
|
||||
class BasicDataSource implements IDataSource {
|
||||
private listeners: DataChangeListener[] = [];
|
||||
private originDataArray: StringData[] = [];
|
||||
|
||||
public totalCount(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public getData(index: number): StringData {
|
||||
return this.originDataArray[index];
|
||||
}
|
||||
|
||||
registerDataChangeListener(listener: DataChangeListener): void {
|
||||
if (this.listeners.indexOf(listener) < 0) {
|
||||
console.info('add listener');
|
||||
this.listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterDataChangeListener(listener: DataChangeListener): void {
|
||||
const pos = this.listeners.indexOf(listener);
|
||||
if (pos >= 0) {
|
||||
console.info('remove listener');
|
||||
this.listeners.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataReload(): void {
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataReloaded();
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataAdd(index: number): void {
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataAdd(index);
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataChange(index: number): void {
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataChange(index);
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataDelete(index: number): void {
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataDelete(index);
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataMove(from: number, to: number): void {
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataMove(from, to);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class MyDataSource extends BasicDataSource {
|
||||
private dataArray: StringData[] = [];
|
||||
|
||||
public totalCount(): number {
|
||||
return this.dataArray.length;
|
||||
}
|
||||
|
||||
public getData(index: number): StringData {
|
||||
return this.dataArray[index];
|
||||
}
|
||||
|
||||
public addData(index: number, data: StringData): void {
|
||||
this.dataArray.splice(index, 0, data);
|
||||
this.notifyDataAdd(index);
|
||||
}
|
||||
|
||||
public pushData(data: StringData): void {
|
||||
this.dataArray.push(data);
|
||||
this.notifyDataAdd(this.dataArray.length - 1);
|
||||
}
|
||||
|
||||
public reloadData(): void {
|
||||
this.notifyDataReload();
|
||||
}
|
||||
}
|
||||
|
||||
class StringData {
|
||||
message: string;
|
||||
imgSrc: string;
|
||||
|
||||
constructor(message: string, imgSrc: string) {
|
||||
this.message = message;
|
||||
this.imgSrc = imgSrc;
|
||||
}
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct TestReuseAbleComponent {
|
||||
@State dataArray: Array<string> = [
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
|
||||
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
|
||||
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
|
||||
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
|
||||
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
|
||||
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
|
||||
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
|
||||
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
|
||||
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
|
||||
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
|
||||
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
|
||||
'https://img-blog.csdnimg.cn/20191215043500229.png',
|
||||
'https://img-blog.csdn.net/20140514114029140',
|
||||
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
|
||||
]
|
||||
private data: MyDataSource = new MyDataSource();
|
||||
private index: number = 0
|
||||
private timeId: number = -1
|
||||
|
||||
aboutToAppear() {
|
||||
for (let i = 0; i <= 4; i++) {
|
||||
this.data.pushData(new StringData(`Hello ${i}`, this.dataArray[i]));
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
List({ space: 3 }) {
|
||||
LazyForEach(this.data, (item: StringData, index: number) => {
|
||||
ListItem() {
|
||||
Column() {
|
||||
Text(item.message).fontSize(50)
|
||||
.onAppear(() => {
|
||||
console.info("appear:" + item.message)
|
||||
})
|
||||
ReusableComponent({ url: item.imgSrc })
|
||||
.width(500)
|
||||
.height(200)
|
||||
}.margin({ left: 10, right: 10 })
|
||||
}
|
||||
.onClick(() => {
|
||||
item.message += '00';
|
||||
this.data.reloadData();
|
||||
})
|
||||
}, (item: StringData, index: number) => JSON.stringify(item))
|
||||
}.cachedCount(5)
|
||||
.onReachEnd(()=>{
|
||||
clearTimeout(this.timeId)
|
||||
this.timeId = setTimeout(()=>{
|
||||
this.data.reloadData()
|
||||
if(this.data.totalCount() <= this.dataArray.length) {
|
||||
this.index = this.data.totalCount()
|
||||
for (let index = this.index; index <= this.index + 4; index++) {
|
||||
this.data.addData(index,new StringData(`Hello ${index}`, this.dataArray[index]));
|
||||
}
|
||||
}
|
||||
},1500)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Reusable
|
||||
@Component
|
||||
struct ReusableComponent {
|
||||
@State url: string = ""
|
||||
|
||||
aboutToReuse(params: Record<string, string>) {
|
||||
this.url = params.url
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption: {
|
||||
loadSrc: this.url,
|
||||
placeholderSrc: $r('app.media.icon_loading')
|
||||
}
|
||||
})
|
||||
}.width("100%").height("100%")
|
||||
}
|
||||
}
|
|
@ -54,6 +54,8 @@
|
|||
"pages/testStopPlayingGifPage",
|
||||
"pages/testImageKnifeDataFetch",
|
||||
"pages/testImageKnifeHeic",
|
||||
"pages/testImageKnifeNetPlaceholder"
|
||||
"pages/testImageKnifeNetPlaceholder",
|
||||
"pages/testCustomDataFetchClientWithPage",
|
||||
"pages/testReuseAblePages"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 { describe, it, expect } from '@ohos/hypium';
|
||||
import { ImageKnife, ImageKnifeGlobal, RequestOption } from '@ohos/imageknife/Index';
|
||||
import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/DefaultJobQueue';
|
||||
import { IJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/IJobQueue';
|
||||
import taskpool from '@ohos.taskpool';
|
||||
import common from '@ohos.app.ability.common';
|
||||
|
||||
export default function DefaultJobQueueTest() {
|
||||
|
||||
describe('DefaultJobQueueTest', () => {
|
||||
it('testJob', 0, () => {
|
||||
let job: IJobQueue = new DefaultJobQueue();
|
||||
job.add(makeRequest("medium1", getContext() as common.UIAbilityContext));
|
||||
job.add(makeRequest("medium2", getContext() as common.UIAbilityContext, taskpool.Priority.MEDIUM));
|
||||
job.add(makeRequest("medium3", getContext() as common.UIAbilityContext));
|
||||
job.add(makeRequest("low1", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
|
||||
job.add(makeRequest("high1", getContext() as common.UIAbilityContext, taskpool.Priority.HIGH));
|
||||
job.add(makeRequest("low2", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
|
||||
job.add(makeRequest("medium4", getContext() as common.UIAbilityContext));
|
||||
|
||||
expect(job.getQueueLength()).assertEqual(7);
|
||||
expect(job.pop()!.loadSrc).assertEqual("high1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium2");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium3");
|
||||
expect(job.pop()!.loadSrc).assertEqual("medium4");
|
||||
expect(job.pop()!.loadSrc).assertEqual("low1");
|
||||
expect(job.pop()!.loadSrc).assertEqual("low2");
|
||||
expect(job.pop()).assertEqual(undefined);
|
||||
expect(job.getQueueLength()).assertEqual(0);
|
||||
});
|
||||
|
||||
it("testMaxRequests", 1, () => {
|
||||
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
|
||||
if (imageKnife) {
|
||||
expect(imageKnife.maxRequests).assertEqual(64);
|
||||
imageKnife.setMaxRequests(10);
|
||||
expect(imageKnife.maxRequests).assertEqual(10);
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function makeRequest(src: string, context: common.UIAbilityContext, priority: taskpool.Priority = taskpool.Priority.MEDIUM): RequestOption {
|
||||
let request: RequestOption = new RequestOption()
|
||||
request.loadSrc = src;
|
||||
request.priority = priority;
|
||||
request.moduleContext = context;
|
||||
return request;
|
||||
}
|
|
@ -20,6 +20,7 @@ import RequestOptionTest from './requestoption.test'
|
|||
import ImageKnifeTest from './imageknife.test'
|
||||
import DiskLruCacheTest from './diskLruCache.test'
|
||||
import SendableDataTest from './SendableData.test'
|
||||
import DefaultJobQueueTest from './DefaultJobQueueTest.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest()
|
||||
|
@ -30,4 +31,5 @@ export default function testsuite() {
|
|||
RequestOptionTest()
|
||||
ImageKnifeTest();
|
||||
SendableDataTest();
|
||||
DefaultJobQueueTest();
|
||||
}
|
|
@ -110,6 +110,8 @@ export {IDataFetch} from './src/main/ets/components/imageknife/networkmanage/IDa
|
|||
export {ICache} from './src/main/ets/components/imageknife/requestmanage/ICache'
|
||||
export { FileTypeUtil } from './src/main/ets/components/imageknife/utils/FileTypeUtil'
|
||||
export { ParseImageUtil } from './src/main/ets/components/imageknife/utils/ParseImageUtil'
|
||||
export { DownloadClient } from './src/main/ets/components/imageknife/networkmanage/DownloadClient';
|
||||
export { CustomDataFetchClient } from './src/main/ets/components/imageknife/networkmanage/CustomDataFetchClient';
|
||||
|
||||
/**
|
||||
* svg parse
|
||||
|
|
|
@ -35,13 +35,16 @@ import http from '@ohos.net.http'
|
|||
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 { DefaultJobQueue } from './utils/DefaultJobQueue';
|
||||
import { IJobQueue } from './utils/IJobQueue';
|
||||
import LightWeightMap from '@ohos.util.LightWeightMap';
|
||||
import List from '@ohos.util.List';
|
||||
import { GIFFrame } from './utils/gif/GIFFrame'
|
||||
import emitter from '@ohos.events.emitter';
|
||||
|
||||
|
@ -68,9 +71,6 @@ export class ImageKnife {
|
|||
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; // 通用文件格式辨别
|
||||
|
@ -87,14 +87,16 @@ export class ImageKnife {
|
|||
// 开发者可配置全局缓存
|
||||
engineKeyImpl: EngineKeyInterface;
|
||||
private mParseImageUtil: IParseImage<PixelMap>;
|
||||
// 最大并发
|
||||
maxRequests: number = 64;
|
||||
// 排队队列
|
||||
private jobQueue: IJobQueue = new DefaultJobQueue();
|
||||
// 执行中的请求
|
||||
private executingJobMap: LightWeightMap<string, List<RequestOption>> = new LightWeightMap();
|
||||
|
||||
private constructor() {
|
||||
this.mParseImageUtil = new ParseImageUtil();
|
||||
|
||||
this.runningMaps = new EasyLinkedHashMap();
|
||||
this.pendingMaps = new EasyLinkedHashMap();
|
||||
this.pausedMaps = new EasyLinkedHashMap();
|
||||
|
||||
// 构造方法传入size 为保存文件个数
|
||||
this.memoryCache = new MemoryLruCache(100, 100 * 1024 * 1024);
|
||||
|
||||
|
@ -204,7 +206,6 @@ export class ImageKnife {
|
|||
return new CompressBuilder();
|
||||
}
|
||||
|
||||
|
||||
// 设置缓存张数,缓存大小,单位字节
|
||||
public setLruCacheSize(size: number, memory: number) {
|
||||
if (this.memoryCache.map.size() <= 0) {
|
||||
|
@ -248,28 +249,6 @@ export class ImageKnife {
|
|||
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())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -277,28 +256,19 @@ export class ImageKnife {
|
|||
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
|
||||
if (this.executingJobMap.length > 0) {
|
||||
this.executingJobMap.forEach((list: List<RequestOption>) => {
|
||||
this.taskpoolLoadResource(list.get(0), Constants.MAIN_HOLDER);
|
||||
})
|
||||
} else {
|
||||
this.dispatchNextJob();
|
||||
}
|
||||
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)
|
||||
}
|
||||
this.executingJobMap.remove(uuid);
|
||||
}
|
||||
|
||||
// 正常加载
|
||||
|
@ -525,111 +495,38 @@ export class ImageKnife {
|
|||
|
||||
// 删除执行结束的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);
|
||||
|
||||
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)
|
||||
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();
|
||||
if (!this.isPaused) {
|
||||
//不暂停则继续加载
|
||||
this.executingJobMap.remove(request.uuid);
|
||||
this.dispatchNextJob();
|
||||
}
|
||||
}
|
||||
|
||||
// 启动新线程 去磁盘取 去网络取
|
||||
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)
|
||||
|
||||
if (this.keyNotEmpty(request)) {
|
||||
if (this.executingJobMap.length > this.maxRequests) {
|
||||
this.jobQueue.add(request);
|
||||
return
|
||||
}
|
||||
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
|
||||
if (requestList == undefined) {
|
||||
requestList = new List();
|
||||
requestList.add(request);
|
||||
this.executingJobMap.set(request.uuid, requestList);
|
||||
if (!this.isPaused) {
|
||||
LogUtil.log("loadCacheManager start uuid : " + request.uuid + " url : " + request.loadSrc);
|
||||
//暂停则不开启加载
|
||||
this.taskpoolLoadResource(request, Constants.MAIN_HOLDER);
|
||||
}
|
||||
} else {
|
||||
requestList.add(request);
|
||||
this.executingJobMap.set(request.uuid, requestList);
|
||||
LogUtil.log("loadCacheManager reuse uuid : " + request.uuid + " url : " + request.loadSrc);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
LogUtil.log("key没有生成无法进入存取!")
|
||||
}
|
||||
} else {
|
||||
LogUtil.log("key没有生成无法进入存取!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -680,6 +577,7 @@ export class ImageKnife {
|
|||
errorholderSrc: this.transformResource(request.errorholderSrc) as PixelMap | MResource | undefined,
|
||||
retryholderSrc:this.transformResource(request.retryholderSrc) as PixelMap | MResource | undefined,
|
||||
fallbackSrc: this.transformResource(request.fallbackSrc) as PixelMap | MResource | undefined,
|
||||
customGetImage: request.customGetImage
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
@ -725,7 +623,12 @@ export class ImageKnife {
|
|||
} else if (usageType == Constants.MAIN_HOLDER && mainCache) {
|
||||
LogUtil.info("imageknife load mainsource from MemoryCache")
|
||||
mainCache.waitSaveDisk = false;
|
||||
request.loadComplete(mainCache);
|
||||
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
|
||||
if(requestList != undefined) {
|
||||
requestList.forEach((requestOption: RequestOption)=>{
|
||||
requestOption.loadComplete(mainCache as ImageKnifeData);
|
||||
})
|
||||
}
|
||||
return;
|
||||
}
|
||||
//组装可以通过sendable传递的数据
|
||||
|
@ -771,12 +674,22 @@ export class ImageKnife {
|
|||
} else {
|
||||
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
|
||||
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
|
||||
request.loadComplete(imageKnifeData)
|
||||
this.memoryCacheProxy.putValue(request.generateCacheKey,imageKnifeData)
|
||||
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid)
|
||||
if(requestList != undefined) {
|
||||
requestList.forEach((requestOption: RequestOption)=>{
|
||||
requestOption.loadComplete(imageKnifeData);
|
||||
})
|
||||
}
|
||||
this.memoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
|
||||
} else if ((data as GIFFrame[]).length > 0) {
|
||||
let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data as GIFFrame[]);
|
||||
request.loadComplete(imageKnifeData)
|
||||
this.memoryCacheProxy.putValue(request.generateCacheKey,imageKnifeData)
|
||||
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
|
||||
if(requestList != undefined) {
|
||||
requestList.forEach((requestOption: RequestOption)=>{
|
||||
requestOption.loadComplete(imageKnifeData);
|
||||
})
|
||||
}
|
||||
this.memoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
|
||||
} else {
|
||||
request.loadError("request resources error")
|
||||
}
|
||||
|
@ -784,7 +697,6 @@ export class ImageKnife {
|
|||
}).catch((err: BusinessError | string) => {
|
||||
request.loadError(err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private keyNotEmpty(request: RequestOption): boolean {
|
||||
|
@ -798,40 +710,6 @@ export class ImageKnife {
|
|||
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)
|
||||
|
@ -876,6 +754,21 @@ export class ImageKnife {
|
|||
|
||||
})
|
||||
}
|
||||
|
||||
// 分发下一个任务
|
||||
dispatchNextJob() {
|
||||
let request: RequestOption | undefined = this.jobQueue.pop();
|
||||
if (request != undefined) {
|
||||
this.loadCacheManager(request);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置请求的最大并发数量
|
||||
setMaxRequests(count: number) {
|
||||
if (count > 0) {
|
||||
this.maxRequests = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -940,6 +833,7 @@ async function taskExecute(sendData:SendableData,taskData:TaskParams): Promise<P
|
|||
newRequestOption.isCacheable = sendData.getIsCacheable();
|
||||
//设置磁盘缓存路径
|
||||
newRequestOption.diskMemoryCachePath = sendData.getDiskMemoryCachePath();
|
||||
newRequestOption.customGetImage = taskData.customGetImage;
|
||||
if (displayProgress) {
|
||||
newRequestOption.addProgressListener({
|
||||
asyncSuccess: (percentValue: number) => {
|
||||
|
|
|
@ -216,7 +216,6 @@ export struct ImageKnifeComponent {
|
|||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
let realSize:Size = {
|
||||
width: this.context.width,
|
||||
height: this.context.height
|
||||
|
@ -312,6 +311,9 @@ export struct ImageKnifeComponent {
|
|||
this.runNextFunction(this.displayRetryholder,data)
|
||||
}})
|
||||
}
|
||||
if (this.imageKnifeOption.customGetImage) {
|
||||
request.customGetImage = this.imageKnifeOption.customGetImage;
|
||||
}
|
||||
}
|
||||
|
||||
configHspContext(request: RequestOption){
|
||||
|
@ -722,6 +724,9 @@ export struct ImageKnifeComponent {
|
|||
aboutToRecycle(){
|
||||
this.resetGifData()
|
||||
}
|
||||
aboutToReuse(params: ESObject) {
|
||||
this.context.clearRect(0,0,this.context.width,this.context.height)
|
||||
}
|
||||
aboutToAppear() {
|
||||
LogUtil.log('ImageKnifeComponent aboutToAppear happened!')
|
||||
this.canvasHasReady = false;
|
||||
|
|
|
@ -27,6 +27,7 @@ import { RoundCorner } from './transform/RoundedCornersTransformation'
|
|||
import { ObjectKey } from './ObjectKey'
|
||||
import common from '@ohos.app.ability.common'
|
||||
import { Priority } from './RequestOption'
|
||||
import { DataFetchResult } from './networkmanage/DataFetchResult'
|
||||
|
||||
export interface CropCircleWithBorder{
|
||||
border: number,
|
||||
|
@ -145,6 +146,9 @@ export class ImageKnifeOption {
|
|||
context?: common.UIAbilityContext;
|
||||
// sizeAnimate?: AnimateParam 由业务自定义不再支持
|
||||
|
||||
// 设置是否使用应用自定义的方式加载图片
|
||||
customGetImage?: (context: Context, src: string) => Promise<DataFetchResult>;
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ import { DiskLruCache } from '../cache/DiskLruCache'
|
|||
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
|
||||
import { FileUtils } from '../cache/FileUtils'
|
||||
import util from '@ohos.util'
|
||||
import { DataFetchResult } from './networkmanage/DataFetchResult'
|
||||
|
||||
export interface Size {
|
||||
width: number,
|
||||
|
@ -149,6 +150,8 @@ export class RequestOption {
|
|||
fallbackCacheKey: string = "";
|
||||
// 自定义缓存关键字
|
||||
signature?: ObjectKey;
|
||||
// 设置是否使用应用自定义的方式加载图片
|
||||
customGetImage?: (context: Context, src: string) => Promise<DataFetchResult>;
|
||||
// 下载原始文件地址
|
||||
downloadFilePath: string = "";
|
||||
//磁盘缓存文件路径
|
||||
|
@ -180,9 +183,6 @@ export class RequestOption {
|
|||
constructor() {
|
||||
// 初始化全局监听
|
||||
this.requestListeners = new Array();
|
||||
// 初始化唯一标识,可以用这个标识找到ImageKnife中的对象
|
||||
this.uuid = this.generateUUID();
|
||||
|
||||
|
||||
let ctx = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext
|
||||
if (ctx != undefined) {
|
||||
|
@ -196,14 +196,7 @@ export class RequestOption {
|
|||
this.transformations = array;
|
||||
}
|
||||
generateUUID(): string {
|
||||
const uuid = util.generateRandomUUID()
|
||||
// let d = new Date().getTime();
|
||||
// const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(new RegExp("[xy]", "g"), (c) => {
|
||||
// const r = (d + Math.random() * 16) % 16 | 0;
|
||||
// d = Math.floor(d / 16);
|
||||
// return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
// });
|
||||
return uuid;
|
||||
return SparkMD5.hashBinary(JSON.stringify(this.loadSrc)) as string;
|
||||
}
|
||||
|
||||
setModuleContext(moduleCtx: common.UIAbilityContext) {
|
||||
|
@ -241,6 +234,8 @@ export class RequestOption {
|
|||
|
||||
load(src: string | PixelMap | Resource) {
|
||||
this.loadSrc = src;
|
||||
// 初始化唯一标识,可以用这个标识找到ImageKnife中的对象
|
||||
this.uuid = this.generateUUID();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import { ObjectKey } from './ObjectKey';
|
|||
import { Priority, Size } from '../imageknife/RequestOption'
|
||||
import common from '@ohos.app.ability.common'
|
||||
import { MResource } from './utils/MResource';
|
||||
import { DataFetchResult } from './networkmanage/DataFetchResult';
|
||||
|
||||
export class TaskParams {
|
||||
headers: Map<string, Object> = new Map<string, Object>();
|
||||
|
@ -27,4 +28,5 @@ export class TaskParams {
|
|||
errorholderSrc: PixelMap | MResource | undefined = undefined;
|
||||
retryholderSrc: PixelMap | MResource | undefined = undefined;
|
||||
fallbackSrc: PixelMap | MResource | undefined = undefined;
|
||||
customGetImage?: (context: Context, loadSrc: string) => Promise<DataFetchResult>;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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 { IDataFetch } from '../networkmanage/IDataFetch'
|
||||
import { RequestOption } from '../RequestOption'
|
||||
import { RequestData } from './RequestData'
|
||||
import { ImageKnifeGlobal } from '../ImageKnifeGlobal'
|
||||
import common from '@ohos.app.ability.common'
|
||||
import http from '@ohos.net.http'
|
||||
import { DataFetchResult } from './DataFetchResult'
|
||||
|
||||
@Sendable
|
||||
export class CustomDataFetchClient implements IDataFetch {
|
||||
async loadData(request: RequestOption) {
|
||||
let result: DataFetchResult = new DataFetchResult();
|
||||
if (!request || typeof request.loadSrc !== 'string') {
|
||||
result.error = 'CustomDataFetchClient request or loadSrc error.';
|
||||
return result;
|
||||
}
|
||||
// 自定义单个图片的网络栈
|
||||
if (request.customGetImage) {
|
||||
return await request.customGetImage(ImageKnifeGlobal.getInstance()
|
||||
.getHapContext() as common.UIAbilityContext, request.loadSrc);
|
||||
}
|
||||
// 所有图片的网络栈
|
||||
try {
|
||||
let httpRequest = http.createHttp()
|
||||
let arrayBuffers = new Array<ArrayBuffer>();
|
||||
httpRequest.on('headersReceive', (header: Object) => {
|
||||
// 跟服务器连接成功准备下载
|
||||
if (request.progressFunc) {
|
||||
// 进度条为0
|
||||
request.progressFunc.asyncSuccess(0)
|
||||
}
|
||||
})
|
||||
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
|
||||
// 下载数据流多次返回
|
||||
arrayBuffers.push(data);
|
||||
})
|
||||
httpRequest.on('dataReceiveProgress', (data: RequestData) => {
|
||||
// 下载进度
|
||||
if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) {
|
||||
let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100)
|
||||
if (request.progressFunc) {
|
||||
request.progressFunc.asyncSuccess(percent)
|
||||
}
|
||||
}
|
||||
})
|
||||
httpRequest.on('dataEnd', () => {
|
||||
// 下载完毕
|
||||
})
|
||||
const headerObj: Record<string, Object> = {}
|
||||
request.headers.forEach((value, key) => {
|
||||
headerObj[key] = value
|
||||
})
|
||||
const data = await httpRequest.requestInStream(request.loadSrc as string, {
|
||||
header: headerObj,
|
||||
method: http.RequestMethod.GET,
|
||||
expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
||||
connectTimeout: 60000, // 可选 默认60000ms
|
||||
readTimeout: 0, // 可选, 默认为60000ms
|
||||
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
|
||||
usingCache: false
|
||||
}).catch((err: Error) => {
|
||||
result.error = 'CustomDataFetchClient has error, http code = ' + JSON.stringify(err);
|
||||
})
|
||||
if (data == 200) {
|
||||
result.data = this.combineArrayBuffers(arrayBuffers);
|
||||
} else {
|
||||
result.error = 'CustomDataFetchClient resultCode error, code = ' + data;
|
||||
}
|
||||
console.log('TestCustomDataFetch all onComplete, code = ' + data + ',length = ' + result.data?.byteLength);
|
||||
} catch (err) {
|
||||
result.error = 'CustomDataFetchClient catch err request uuid =' + request.uuid;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
combineArrayBuffers(arrayBuffers: ArrayBuffer[]): ArrayBuffer {
|
||||
// 计算多个ArrayBuffer的总字节大小
|
||||
let totalByteLength = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
totalByteLength += arrayBuffer.byteLength;
|
||||
}
|
||||
|
||||
// 创建一个新的ArrayBuffer
|
||||
const combinedArrayBuffer = new ArrayBuffer(totalByteLength);
|
||||
|
||||
// 创建一个Uint8Array来操作新的ArrayBuffer
|
||||
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
|
||||
|
||||
// 依次复制每个ArrayBuffer的内容到新的ArrayBuffer中
|
||||
let offset = 0;
|
||||
for (const arrayBuffer of arrayBuffers) {
|
||||
const sourceUint8Array = new Uint8Array(arrayBuffer);
|
||||
combinedUint8Array.set(sourceUint8Array, offset);
|
||||
offset += sourceUint8Array.length;
|
||||
}
|
||||
return combinedArrayBuffer;
|
||||
}
|
||||
}
|
|
@ -35,11 +35,7 @@ export class DownloadClient implements IDataFetch {
|
|||
|
||||
async loadData(request: RequestOption): Promise<DataFetchResult> {
|
||||
if (typeof request.loadSrc == 'string') {
|
||||
let fileDir:string = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string;
|
||||
let cacheDir:string = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).cacheDir as string
|
||||
|
||||
if (request.loadSrc.startsWith(fileDir) ||
|
||||
request.loadSrc.startsWith(cacheDir)) {
|
||||
if (this.isLocalLoadSrc(ImageKnifeGlobal.getInstance().getHapContext(), request.loadSrc)) {
|
||||
// 本地沙盒
|
||||
return this.localFileClient.loadData(request)
|
||||
} else if (request.loadSrc.startsWith('datashare://') || request.loadSrc.startsWith('file://')) {
|
||||
|
@ -54,4 +50,15 @@ export class DownloadClient implements IDataFetch {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
isLocalLoadSrc(context: Object | undefined, loadSrc: string): boolean {
|
||||
if (context != undefined) {
|
||||
let fileDir: string = (context as common.UIAbilityContext).filesDir as string;
|
||||
let cacheDir: string = (context as common.UIAbilityContext).cacheDir as string
|
||||
if (loadSrc.startsWith(fileDir) || loadSrc.startsWith(cacheDir)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -70,6 +70,7 @@ export class HttpDownloadClient implements IDataFetch {
|
|||
} else {
|
||||
result.error = `HttpDownloadClient has error, http code = ` + JSON.stringify(data);
|
||||
}
|
||||
console.log('TestCustomDataFetch http onComplete, code = ' + data + ',length = ' + result.data?.byteLength);
|
||||
} catch (err) {
|
||||
result.error ='HttpDownloadClient catch err request uuid =' + request.uuid;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 { IJobQueue } from './IJobQueue';
|
||||
import Queue from '@ohos.util.Queue';
|
||||
import taskpool from '@ohos.taskpool';
|
||||
import { RequestOption } from '../RequestOption';
|
||||
|
||||
export class DefaultJobQueue implements IJobQueue {
|
||||
highQueue: Queue<RequestOption> = new Queue();
|
||||
normalQueue: Queue<RequestOption> = new Queue();
|
||||
lowQueue: Queue<RequestOption> = new Queue();
|
||||
|
||||
getQueueLength(): number {
|
||||
return this.highQueue.length + this.normalQueue.length + this.lowQueue.length;
|
||||
}
|
||||
|
||||
add(request: RequestOption): void {
|
||||
if (request.priority === undefined || request.priority === taskpool.Priority.MEDIUM) {
|
||||
this.normalQueue.add(request);
|
||||
} else if (request.priority === taskpool.Priority.HIGH) {
|
||||
this.highQueue.add(request);
|
||||
} else {
|
||||
this.lowQueue.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
pop(): RequestOption | undefined {
|
||||
if (this.highQueue.length > 0) {
|
||||
return this.highQueue.pop();
|
||||
} else if (this.normalQueue.length > 0) {
|
||||
return this.normalQueue.pop();
|
||||
} else {
|
||||
return this.lowQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { RequestOption } from '../../imageknife/RequestOption';
|
||||
|
||||
export interface IJobQueue {
|
||||
|
||||
/**
|
||||
* 获取队列长度
|
||||
* @returns
|
||||
*/
|
||||
getQueueLength(): number;
|
||||
|
||||
/**
|
||||
* 往队列中添加元素
|
||||
* @param RequestObject
|
||||
*/
|
||||
add(request: RequestOption): void;
|
||||
|
||||
/**
|
||||
* 移除并返回队列头部的元素
|
||||
* @returns
|
||||
*/
|
||||
pop(): RequestOption | undefined;
|
||||
}
|
|
@ -110,6 +110,8 @@ export {IDataFetch} from '@ohos/imageknife'
|
|||
export {ICache} from '@ohos/imageknife'
|
||||
export { FileTypeUtil } from '@ohos/imageknife'
|
||||
export { ParseImageUtil } from '@ohos/imageknife'
|
||||
export { DownloadClient } from '@ohos/imageknife'
|
||||
export { CustomDataFetchClient } from '@ohos/imageknife'
|
||||
|
||||
/**
|
||||
* svg parse
|
||||
|
|
Loading…
Reference in New Issue