1# @ohos.arkui.Prefetcher (Prefetching)
2Used in conjunction with **LazyForEach**, the **Prefetcher** module provides content prefetching capabilities for container components such as **List**, **Grid**, **Waterfall**, and **Swiper** during scrolling, to enhance the user browsing experience.
3
4>  **NOTE**
5>
6>  The initial APIs of this module are supported since API version 12. Updates will be marked with a superscript to indicate their earliest API version.
7
8## Modules to Import
9
10```ts
11import { BasicPrefetcher, IDataSourcePrefetching, IPrefetcher } from '@kit.ArkUI';
12```
13
14
15## IPrefetcher
16Implement this API to provide prefetching capabilities.
17
18**Atomic service API**: This API can be used in atomic services since API version 12.
19
20**System capability**: SystemCapability.ArkUI.ArkUI.Full
21
22### setDataSource
23setDataSource(dataSource: IDataSourcePrefetching): void;
24
25Sets the prefetching-capable data source to bind to the **Prefetcher** object.
26
27**Atomic service API**: This API can be used in atomic services since API version 12.
28
29**System capability**: SystemCapability.ArkUI.ArkUI.Full
30
31**Parameters**
32
33| Name       | Type                                               | Mandatory| Description        |
34|------------|---------------------------------------------------|----|------------|
35| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | Yes | Prefetching-capable data source.|
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
54Called when the boundaries of the visible area change. It works with the **List**, **Grid**, **Waterfall**, and **Swiper** components.
55
56**Atomic service API**: This API can be used in atomic services since API version 12.
57
58**System capability**: SystemCapability.ArkUI.ArkUI.Full
59
60**Parameters**
61
62| Name       | Type    | Mandatory| Description       |
63|------------|--------|----|-----------|
64| minVisible | number | Yes | Upper bound of the visible area.|
65| maxVisible | number | Yes | Lower bound of the visible area.|
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
82As a fundamental implementation of **IPrefetcher**, offers an intelligent data prefetching algorithm that decides which data items to prefetch based on real-time changes in the visible area on the screen and variations in the prefetch duration. It can also determine which prefetch requests should be canceled based on the user's scrolling actions.
83
84**Atomic service API**: This API can be used in atomic services since API version 12.
85
86**System capability**: SystemCapability.ArkUI.ArkUI.Full
87
88### constructor
89constructor(dataSource?: IDataSourcePrefetching)
90
91A constructor used to create a **DataSource** instance.
92
93**Atomic service API**: This API can be used in atomic services since API version 12.
94
95**System capability**: SystemCapability.ArkUI.ArkUI.Full
96
97**Parameters**
98
99| Name       | Type                                               | Mandatory| Description        |
100|------------|---------------------------------------------------|----|------------|
101| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | No | Prefetching-capable data source.|
102
103### setDataSource
104setDataSource(dataSource: IDataSourcePrefetching): void;
105
106Sets the prefetching-capable data source to bind to the **Prefetcher** object.
107
108**Atomic service API**: This API can be used in atomic services since API version 12.
109
110**System capability**: SystemCapability.ArkUI.ArkUI.Full
111
112**Parameters**
113
114| Name       | Type                                               | Mandatory| Description        |
115|------------|---------------------------------------------------|----|------------|
116| dataSource | [IDataSourcePrefetching](#idatasourceprefetching) | Yes | Prefetching-capable data source.|
117
118### visibleAreaChanged
119visibleAreaChanged(minVisible: number, maxVisible: number): void
120
121Called when the boundaries of the visible area change. It works with the **List**, **Grid**, **Waterfall**, and **Swiper** components.
122
123**Atomic service API**: This API can be used in atomic services since API version 12.
124
125**System capability**: SystemCapability.ArkUI.ArkUI.Full
126
127**Parameters**
128
129| Name       | Type    | Mandatory| Description       |
130|------------|--------|----|-----------|
131| minVisible | number | Yes | Upper bound of the visible area.|
132| maxVisible | number | Yes | Lower bound of the visible area.|
133
134## IDataSourcePrefetching
135
136Implements a prefetching-capable data source.
137
138**Atomic service API**: This API can be used in atomic services since API version 12.
139
140**System capability**: SystemCapability.ArkUI.ArkUI.Full
141
142### prefetch
143**Atomic service API**: This API can be used in atomic services since API version 12.
144
145**System capability**: SystemCapability.ArkUI.ArkUI.Full
146
147**Parameters**
148
149| Name  | Type    | Mandatory| Description      |
150|-------|--------|----|----------|
151| index | number | Yes | Index of the data item to be prefetched.|
152
153### cancel
154**Atomic service API**: This API can be used in atomic services since API version 12.
155
156**System capability**: SystemCapability.ArkUI.ArkUI.Full
157
158**Parameters**
159
160| Name  | Type    | Mandatory| Description        |
161|-------|--------|----|------------|
162| index | number | Yes | Index of the data item whose prefetching should be canceled.|
163
164When list content moves off the screen (for example, during fast scrolling scenarios), once the prefetching algorithm determines which items outside the screen can have their prefetching canceled, this API is called. For instance, if the HTTP framework supports request cancellation, network requests initiated in the **prefetch** API can be canceled here.
165
166## Example
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    // Perform time-consuming operations.
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```
341