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