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实现该接口,提供具备预取能力的DataSource 137 138**元服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 139 140**系统能力:** SystemCapability.ArkUI.ArkUI.Full 141 142### prefetch 143**元服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 144 145**系统能力:** SystemCapability.ArkUI.ArkUI.Full 146 147**参数说明:** 148 149| 参数名 | 类型 | 必填 | 说明 | 150|-------|--------|----|----------| 151| index | number | 是 | 预取数据项索引值 | 152 153### cancel 154**元服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 155 156**系统能力:** SystemCapability.ArkUI.ArkUI.Full 157 158**参数说明:** 159 160| 参数名 | 类型 | 必填 | 说明 | 161|-------|--------|----|------------| 162| index | number | 是 | 取消预取数据项索引值 | 163 164列表内容移出屏幕时(比如列表快速滑动场景下),预取算法判断屏幕以外的Item可以被取消预取时,该方法即会被调用。例如,如果HTTP框架支持请求取消,则可以在此处取消在prefetch中发起的网络请求。 165 166## 示例 167 168```typescript 169import { BasicPrefetcher, IDataSourcePrefetching } from '@kit.ArkUI'; 170import { image } from '@kit.ImageKit'; 171 172const ITEMS_ON_SCREEN = 8; 173 174@Entry 175@Component 176struct PrefetcherDemoComponent { 177 private readonly dataSource = new MyDataSource(2000, 500); 178 private readonly prefetcher = new BasicPrefetcher(this.dataSource); 179 180 build() { 181 Column() { 182 List() { 183 LazyForEach(this.dataSource, (item: PictureItem) => { 184 ListItem() { 185 PictureItemComponent({ info: item }) 186 .height(`${100 / ITEMS_ON_SCREEN}%`) 187 } 188 }, (item: PictureItem) => item.title) 189 } 190 .onScrollIndex((start: number, end: number) => { 191 this.prefetcher.visibleAreaChanged(start, end); 192 }) 193 } 194 } 195} 196 197@Component 198struct PictureItemComponent { 199 @ObjectLink info: PictureItem; 200 201 build() { 202 Row() { 203 Image(this.info.imagePixelMap) 204 .objectFit(ImageFit.Contain) 205 .width('40%') 206 Text(this.info.title) 207 .width('60%') 208 } 209 } 210} 211 212@Observed 213class PictureItem { 214 readonly color: number; 215 title: string; 216 imagePixelMap: image.PixelMap | undefined; 217 key: string; 218 219 constructor(color: number, title: string) { 220 this.color = color; 221 this.title = title; 222 this.key = title; 223 } 224} 225 226type ItemIndex = number; 227type TimerId = number; 228 229class MyDataSource implements IDataSourcePrefetching { 230 private readonly items: PictureItem[]; 231 private readonly fetchDelayMs: number; 232 private readonly fetches: Map<ItemIndex, TimerId> = new Map(); 233 234 constructor(numItems: number, fetchDelayMs: number) { 235 this.items = []; 236 this.fetchDelayMs = fetchDelayMs; 237 for (let i = 0; i < numItems; i++) { 238 const item = new PictureItem(getRandomColor(), `Item ${i}`) 239 this.items.push(item); 240 } 241 } 242 243 async prefetch(index: number): Promise<void> { 244 const item = this.items[index]; 245 if (item.imagePixelMap) { 246 return; 247 } 248 249 // 模拟高耗时操作 250 return new Promise<void>(resolve => { 251 const timeoutId = setTimeout(async () => { 252 this.fetches.delete(index); 253 const bitmap = create10x10Bitmap(item.color); 254 const imageSource: image.ImageSource = image.createImageSource(bitmap); 255 item.imagePixelMap = await imageSource.createPixelMap(); 256 resolve(); 257 }, this.fetchDelayMs); 258 259 this.fetches.set(index, timeoutId) 260 }); 261 } 262 263 cancel(index: number): void { 264 const timerId = this.fetches.get(index); 265 if (timerId) { 266 this.fetches.delete(index); 267 clearTimeout(timerId); 268 } 269 } 270 271 totalCount(): number { 272 return this.items.length; 273 } 274 275 getData(index: number): PictureItem { 276 return this.items[index]; 277 } 278 279 registerDataChangeListener(_: DataChangeListener): void { 280 } 281 282 unregisterDataChangeListener(_: DataChangeListener): void { 283 } 284} 285 286function getRandomColor(): number { 287 const maxColorCode = 256; 288 const r = Math.floor(Math.random() * maxColorCode); 289 const g = Math.floor(Math.random() * maxColorCode); 290 const b = Math.floor(Math.random() * maxColorCode); 291 292 return (r * 256 + g) * 256 + b; 293} 294 295function create10x10Bitmap(color: number): ArrayBuffer { 296 const height = 10; 297 const width = 10; 298 299 const fileHeaderLength = 14; 300 const bitmapInfoLength = 40; 301 const headerLength = fileHeaderLength + bitmapInfoLength; 302 const pixelSize = (width * 3 + 2) * height; 303 304 let length = pixelSize + headerLength; 305 306 const buffer = new ArrayBuffer(length); 307 const view16 = new Uint16Array(buffer); 308 309 view16[0] = 0x4D42; 310 view16[1] = length & 0xffff; 311 view16[2] = length >> 16; 312 view16[5] = headerLength; 313 314 let offset = 7; 315 view16[offset++] = bitmapInfoLength & 0xffff; 316 view16[offset++] = bitmapInfoLength >> 16; 317 view16[offset++] = width & 0xffff; 318 view16[offset++] = width >> 16; 319 view16[offset++] = height & 0xffff; 320 view16[offset++] = height >> 16; 321 view16[offset++] = 1; 322 view16[offset++] = 24; 323 324 const b = color & 0xff; 325 const g = (color >> 8) & 0xff; 326 const r = color >> 16; 327 offset = headerLength; 328 const view8 = new Uint8Array(buffer); 329 for (let y = 0; y < height; y++) { 330 for (let x = 0; x < width; x++) { 331 view8[offset++] = b; 332 view8[offset++] = g; 333 view8[offset++] = r; 334 } 335 offset += 2; 336 } 337 338 return buffer; 339} 340```