1# @ohos.arkui.Prefetcher (Prefetching) 2配合LazyForEach,为List、Grid、Waterfall和Swiper等容器组件滑动浏览时提供内容预加载能力,提升用户浏览体验。 3 4> **说明:** 5> 6> 本模块首批接口从API version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 7 8## 导入模块 9 10```ts 11import { BasicPrefetcher, IDataSourcePrefetching, IPrefetcher } from '@kit.ArkUI'; 12``` 13 14 15## IPrefetcher 16实现此接口以提供预取能力。 17 18**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 19 20**系统能力:** SystemCapability.ArkUI.ArkUI.Full 21 22### setDataSource 23setDataSource(dataSource: IDataSourcePrefetching): void; 24 25设置支持预取的DataSource以绑定到Prefetcher 26 27**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 28 29**系统能力:** SystemCapability.ArkUI.ArkUI.Full 30 31**参数:** 32 33| 参数名 | 类型 | 必填 | 说明 | 34|------------|---------------------------------------------------|----|------------| 35| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | 是 | 支持预取能力的数据源 | 36 37```typescript 38class MyPrefetcher implements IPrefetcher { 39 private dataSource?: IDataSourcePrefetching; 40 41 setDataSource(dataSource: IDataSourcePrefetching): void { 42 this.dataSource = dataSource; 43 } 44 45 visibleAreaChanged(minVisible: number, maxVisible: number): void { 46 this.dataSource?.prefetch(minVisible); 47 } 48} 49``` 50 51### visibleAreaChanged 52visibleAreaChanged(minVisible: number, maxVisible: number): void; 53 54当可见区域边界发生改变时调用此方法。支持与`List`、`Grid`、`Waterfall`和`Swiper`组件配合使用 55 56**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 57 58**系统能力:** SystemCapability.ArkUI.ArkUI.Full 59 60**参数:** 61 62| 参数名 | 类型 | 必填 | 说明 | 63|------------|--------|----|-----------| 64| minVisible | number | 是 | 列表可见区域的上界 | 65| maxVisible | number | 是 | 列表可见区域的下界 | 66 67```typescript 68class MyPrefetcher implements IPrefetcher { 69 private dataSource?: IDataSourcePrefetching; 70 71 setDataSource(dataSource: IDataSourcePrefetching): void { 72 this.dataSource = dataSource; 73 } 74 75 visibleAreaChanged(minVisible: number, maxVisible: number): void { 76 this.dataSource?.prefetch(minVisible); 77 } 78} 79``` 80 81## BasicPrefetcher 82BasicPrefetcher是IPrefetcher的基础实现。它提供了一种智能数据预取算法,以根据屏幕上可见区域的实时变化和预取持续时间的变化来决定应预取哪些数据项。它还可以根据用户的滚动操作来确定哪些预取请求应该被取消。 83 84**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 85 86**系统能力:** SystemCapability.ArkUI.ArkUI.Full 87 88### constructor 89constructor(dataSource?: IDataSourcePrefetching); 90 91传入支持预取的DataSource以绑定到Prefetcher 92 93**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 94 95**系统能力:** SystemCapability.ArkUI.ArkUI.Full 96 97**参数:** 98 99| 参数名 | 类型 | 必填 | 说明 | 100|------------|---------------------------------------------------|----|------------| 101| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | 否 | 支持预取能力的数据源 | 102 103### setDataSource 104setDataSource(dataSource: IDataSourcePrefetching): void; 105 106设置支持预取的DataSource以绑定到Prefetcher 107 108**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 109 110**系统能力:** SystemCapability.ArkUI.ArkUI.Full 111 112**参数:** 113 114| 参数名 | 类型 | 必填 | 说明 | 115|------------|---------------------------------------------------|----|------------| 116| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | 是 | 支持预取能力的数据源 | 117 118### visibleAreaChanged 119visibleAreaChanged(minVisible: number, maxVisible: number): void; 120 121当可见区域边界发生改变时调用此方法。支持与`List`、`Grid`、`Waterfall`和`Swiper`组件配合使用 122 123**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 124 125**系统能力:** SystemCapability.ArkUI.ArkUI.Full 126 127**参数:** 128 129| 参数名 | 类型 | 必填 | 说明 | 130|------------|--------|----|-----------| 131| minVisible | number | 是 | 列表可见区域的上界 | 132| maxVisible | number | 是 | 列表可见区域的下界 | 133 134## IDataSourcePrefetching 135 136继承自[IDataSource](./arkui-ts/ts-rendering-control-lazyforeach.md#idatasource10)。实现该接口,提供具备预取能力的DataSource。 137 138**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 139 140**系统能力:** SystemCapability.ArkUI.ArkUI.Full 141 142### prefetch 143prefetch(index: number): Promise\<void\> | void; 144 145从数据集中预取指定的元素。该方法可以为同步,也可为异步。 146 147**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 148 149**系统能力:** SystemCapability.ArkUI.ArkUI.Full 150 151**参数:** 152 153| 参数名 | 类型 | 必填 | 说明 | 154|-------|--------|----|----------| 155| index | number | 是 | 预取数据项索引值 | 156 157### cancel 158cancel?(index: number): Promise\<void\> | void; 159 160取消从数据集中预取指定的元素。该方法可以为同步,也可为异步。 161 162**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 163 164**系统能力:** SystemCapability.ArkUI.ArkUI.Full 165 166**参数:** 167 168| 参数名 | 类型 | 必填 | 说明 | 169|-------|--------|----|------------| 170| index | number | 是 | 取消预取数据项索引值 | 171 172列表内容移出屏幕时(比如列表快速滑动场景下),预取算法判断屏幕以外的Item可以被取消预取时,该方法即会被调用。例如,如果HTTP框架支持请求取消,则可以在此处取消在prefetch中发起的网络请求。 173 174## 示例 175 176下面示例展示了Prefetcher配合LazyForEach实现的懒加载效果。 177 178```typescript 179import { BasicPrefetcher, IDataSourcePrefetching } from '@kit.ArkUI'; 180import { image } from '@kit.ImageKit'; 181 182const ITEMS_ON_SCREEN = 8; 183 184@Entry 185@Component 186struct PrefetcherDemoComponent { 187 private readonly dataSource = new MyDataSource(2000, 500); 188 private readonly prefetcher = new BasicPrefetcher(this.dataSource); 189 190 build() { 191 Column() { 192 List() { 193 LazyForEach(this.dataSource, (item: PictureItem) => { 194 ListItem() { 195 PictureItemComponent({ info: item }) 196 .height(`${100 / ITEMS_ON_SCREEN}%`) 197 } 198 }, (item: PictureItem) => item.title) 199 } 200 .onScrollIndex((start: number, end: number) => { 201 this.prefetcher.visibleAreaChanged(start, end); 202 }) 203 } 204 } 205} 206 207@Component 208struct PictureItemComponent { 209 @ObjectLink info: PictureItem; 210 211 build() { 212 Row() { 213 Image(this.info.imagePixelMap) 214 .objectFit(ImageFit.Contain) 215 .width('40%') 216 Text(this.info.title) 217 .width('60%') 218 } 219 } 220} 221 222@Observed 223class PictureItem { 224 readonly color: number; 225 title: string; 226 imagePixelMap: image.PixelMap | undefined; 227 key: string; 228 229 constructor(color: number, title: string) { 230 this.color = color; 231 this.title = title; 232 this.key = title; 233 } 234} 235 236type ItemIndex = number; 237type TimerId = number; 238 239class MyDataSource implements IDataSourcePrefetching { 240 private readonly items: PictureItem[]; 241 private readonly fetchDelayMs: number; 242 private readonly fetches: Map<ItemIndex, TimerId> = new Map(); 243 244 constructor(numItems: number, fetchDelayMs: number) { 245 this.items = []; 246 this.fetchDelayMs = fetchDelayMs; 247 for (let i = 0; i < numItems; i++) { 248 const item = new PictureItem(getRandomColor(), `Item ${i}`) 249 this.items.push(item); 250 } 251 } 252 253 async prefetch(index: number): Promise<void> { 254 const item = this.items[index]; 255 if (item.imagePixelMap) { 256 return; 257 } 258 259 // 模拟高耗时操作 260 return new Promise<void>(resolve => { 261 const timeoutId = setTimeout(async () => { 262 this.fetches.delete(index); 263 const bitmap = create10x10Bitmap(item.color); 264 const imageSource: image.ImageSource = image.createImageSource(bitmap); 265 item.imagePixelMap = await imageSource.createPixelMap(); 266 resolve(); 267 }, this.fetchDelayMs); 268 269 this.fetches.set(index, timeoutId) 270 }); 271 } 272 273 cancel(index: number): void { 274 const timerId = this.fetches.get(index); 275 if (timerId) { 276 this.fetches.delete(index); 277 clearTimeout(timerId); 278 } 279 } 280 281 totalCount(): number { 282 return this.items.length; 283 } 284 285 getData(index: number): PictureItem { 286 return this.items[index]; 287 } 288 289 registerDataChangeListener(_: DataChangeListener): void { 290 } 291 292 unregisterDataChangeListener(_: DataChangeListener): void { 293 } 294} 295 296function getRandomColor(): number { 297 const maxColorCode = 256; 298 const r = Math.floor(Math.random() * maxColorCode); 299 const g = Math.floor(Math.random() * maxColorCode); 300 const b = Math.floor(Math.random() * maxColorCode); 301 302 return (r * 256 + g) * 256 + b; 303} 304 305function create10x10Bitmap(color: number): ArrayBuffer { 306 const height = 10; 307 const width = 10; 308 309 const fileHeaderLength = 14; 310 const bitmapInfoLength = 40; 311 const headerLength = fileHeaderLength + bitmapInfoLength; 312 const pixelSize = (width * 3 + 2) * height; 313 314 let length = pixelSize + headerLength; 315 316 const buffer = new ArrayBuffer(length); 317 const view16 = new Uint16Array(buffer); 318 319 view16[0] = 0x4D42; 320 view16[1] = length & 0xffff; 321 view16[2] = length >> 16; 322 view16[5] = headerLength; 323 324 let offset = 7; 325 view16[offset++] = bitmapInfoLength & 0xffff; 326 view16[offset++] = bitmapInfoLength >> 16; 327 view16[offset++] = width & 0xffff; 328 view16[offset++] = width >> 16; 329 view16[offset++] = height & 0xffff; 330 view16[offset++] = height >> 16; 331 view16[offset++] = 1; 332 view16[offset++] = 24; 333 334 const b = color & 0xff; 335 const g = (color >> 8) & 0xff; 336 const r = color >> 16; 337 offset = headerLength; 338 const view8 = new Uint8Array(buffer); 339 for (let y = 0; y < height; y++) { 340 for (let x = 0; x < width; x++) { 341 view8[offset++] = b; 342 view8[offset++] = g; 343 view8[offset++] = r; 344 } 345 offset += 2; 346 } 347 348 return buffer; 349} 350```