OpenHarmony开发者论坛
标题:
使用三方库Imageknife实现列表动态预加载
[打印本页]
作者:
马迪
时间:
2024-9-17 15:47
标题:
使用三方库Imageknife实现列表动态预加载
[md]## 背景
列表是应用开发中最常见的一类开发场景,它可以将杂乱的信息整理成有规律、易于理解和操作的形式,便于用户查找和获取所需要的信息。应用程序中常见的列表场景有新闻列表、购物车列表、各类排行榜等。随着信息数据的累积,特别是一些新闻应用、购物应用、聊天应用,列表数据往往会达到上万条,针对这类大量数据加载的长列表应用,如何对长列表的性能进行优化是非常重要的。一个正确、高性能的长列表应用能明显降低列表渲染时间、提升页面的滑动帧率、降低应用内存占用,大幅提升用户体验。
针对长列表加载这一场景,通常会使用5种优化手段,通过这些优化手段的单个使用或组合使用,可以对列表渲染时间、页面滑动帧率、应用内存占用等方面带来优化,提升性能和用户体验:
- 懒加载:提供列表数据按需加载能力,解决一次性加载长列表数据耗时长、占用过多资源的问题,可以提升页面响应速度。
- 缓存列表项:提供屏幕可视区域外列表项长度的自定义调节能力,配合懒加载设置可缓存列表项参数,通过预加载数据提升列表滑动体验。
- 动态预加载:根据历史任务加载耗时情况,动态调整屏幕可视区域外数据预取数量,配合懒加载设置,可在列表不断滑动时,屏幕可视区外实时更新列表数据,通过预取和预渲染数据提升列表滑动体验。
- 组件复用:提供可复用组件对象的缓存资源池,通过重复使用已经创建过并缓存的组件对象,降低相同组件短时间内频繁创建和销毁的开销,提升组件渲染效率。
- 布局优化:使用扁平化布局方案,减少视图嵌套层级和组件数,避免过度绘制,提升页面渲染效率。
## 预加载方案
而三方库ImageKnife自带图片缓存特性,结合懒加载的使用,可以有效提升图片加载的效率,解决白块问题。此外ImageKnife还提供了preLoadCache方法可以预加载图片。本文将介绍ImageKnife的preLoadCache预加载方法如何结合列表LazyForEach懒加载使用:
- 实现DataSourcePrefetchingImageKnife类,继承IDataSourcePrefetching接口,并实现prefetch和cancel方法
其中 prefetch做图片的请求和缓存处理。cancel在组件不可视区域取消请求。
```
export default class DataSourcePrefetchingImageKnife implements IDataSourcePrefetching {
private dataArray: Array<InfoItem>
private listeners: DataChangeListener[] = [];
constructor(dataArray: Array<InfoItem>) {
this.dataArray = dataArray;
}
public getData(index: number) {
return this.dataArray[index]
}
public totalCount(): number {
return this.dataArray.length
}
public addData(index: number, data: InfoItem[]): 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)
})
}
async prefetch(index: number): Promise<void> {
let item = this.dataArray[index]
try {
if (typeof item.albumUrl == "string") {
// 图片预加载
await ImageKnife.getInstance().preLoadCache(item.albumUrl)
}
} catch (err) {
// 预加载失败,展示错误图
item.albumUrl = IMADE_UNAVAILABLE
}
}
// 取消请求处理
cancel(index: number) {
// ImageKnifeComponent 内部触发aboutToDisAppear生命周期会将请求取消
}
}
```
- 在应用列表界面,首先创建DataSourcePrefetchingImageKnife、BasicPrefetcher对象,然后在List的onScrollIndex回调中调用BasicPrefetcher的visibleAreaChanged方法,传入List的可见区域起始坐标。至此完成代码的优化。
```
@ComponentV2
export struct PrefetchAndPreload {
// 创建DataSourcePrefetchingImageKnife对象,具备任务预取、取消能力的数据源
private readonly dataSource = new DataSourcePrefetchingImageKnife(PageViewModel.getItems());
// 创建BasicPrefetcher对象,默认的动态预取算法实现
private readonly prefetcher = new BasicPrefetcher(this.dataSource);
build() {
Column() {
List({ space: 16 }) {
LazyForEach(this.dataSource, (item: InfoItem,index:number) => {
ListItem() {
Column({ space: 12 }) {
ImageKnifeComponent({
imageKnifeOption:new ImageKnifeOption({
loadSrc: item.albumUrl,
placeholderSrc
r('app.media.loading')
})
}).width(100).height(100)
Text(`${index}`)
}.border({ width: 5 , color: "#000000"})
}
.reuseId('imageKnife')
})
}
.cachedCount(5)
.onScrollIndex((start: number, end: number) => {
// 列表滚动触发visibleAreaChanged,实时更新预取范围,触发调用prefetch、cancel接口
this.prefetcher.visibleAreaChanged(start, end)
})
.width("100%")
.height("100%")
.margin({ left: 10, right: 10 })
.layoutWeight(1)
}
}
}
```
## 实现原理
参考[长列表优化概述](
https://developer.huawei.com/con ... ction11667144010222
)
## 预加载效果
如下对比场景设置数据cachedCount=5、cachedCount=30和动态预加载:
| cachedCount=5 | cachedCount=30 | 动态预加载 |
| --- | --- | --- |
| | ||
| 数据设置 | 首屏加载| 滑动过程滑块数量|
| --- | --- | --- |
| cachedCount=5 | 首屏加载快(首屏加载可视区+5张) | 滑动过程中白块很多 |
| cachedCount=30 | 首屏概率加载慢(首屏加载可视区+30张) | 滑动过程中没有白块或很少 |
| 动态预加载 | 首屏加载快(首屏加载可视区+5张;再加载不可视区域图片) | 滑动过程中没有白块或很少 |
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5