ArkTS懶加載LazyForEach的基本使用

在 ArkTS 的開發中,如果你要渲染一個很長的列表,比如商品列表、評論列表或者朋友圈動態,用傳統的循環結構(比如 ForEach)很容易導致性能問題,尤其是加載慢、卡頓甚至內存暴漲。

這時候就要用到 懶加載渲染組件——LazyForEach

LazyForEach 是 ArkTS 提供的一種 延遲渲染列表項的方式。只有當列表項真正要被顯示在屏幕上時,相關組件才會被創建和渲染,從而節省內存和提升性能。

可以把它理解成 ArkTS 中的“虛擬滾動列表”。

LazyForEach的使用限制

  • LazyForEach必須在容器組件內使用僅有List、Grid、Swiper以及WaterFlow組件支持數據懶加載(可配置cachedCount屬性,即只加載可視部分以及其前后少量數據用于緩沖),其他組件仍然是一次性加載所有的數據。支持數據懶加載的父組件根據自身及子組件的高度或寬度計算可視區域內需布局的子節點數量,高度或寬度的缺失會導致部分場景懶加載失效

catchdCount

List設置cachedCount后,顯示區域外上下各會預加載并布局cachedCount行ListItem。

  • LazyForEach依賴生成的鍵值判斷是否刷新子組件,鍵值不變則不觸發刷新。
  • 容器組件內只能包含一個LazyForEach。以List為例,不推薦同時包含ListItem、ForEach、LazyForEach。也不推薦同時包含多個LazyForEach。
  • LazyForEach在每次迭代中,必須創建且只允許創建一個子組件;即LazyForEach的子組件生成函數有且只有一個根組件
  • 生成的子組件必須是允許包含在LazyForEach父容器組件中的子組件。
  • 允許LazyForEach包含在if/else條件渲染語句中,也允許LazyForEach中出現if/else條件渲染語句。
  • 鍵值生成器必須針對每個數據生成唯一的值,如果鍵值相同,將導致鍵值相同的UI組件渲染出現問題。
  • LazyForEach必須使用DataChangeListener對象進行更新。重新賦值第一個參數dataSource會導致異常;dataSource使用狀態變量時,狀態變量改變不會觸發LazyForEach的UI刷新
  • 為了高性能渲染,使用DataChangeListener對象的onDataChange方法更新UI時,需要生成不同于原來的鍵值來觸發組件刷新。

LazyForEach鍵值生成規則

LazyForEach提供了參數keyGenerator,開發者可以使用該函數生成自定義鍵值。如果未定義keyGenerator函數,ArkUI框架將使用默認的鍵值生成函數:(item: Object, index: number) => { return viewId + ‘-’ + index.toString(); }。viewId在編譯器轉換過程中生成,同一個LazyForEach組件內的viewId一致。

基本語法

LazyForEach(dataSource: IDataSource,             // 需要進行數據迭代的數據源itemGenerator: (item: any, index?: number) => void,  // 子組件生成函數keyGenerator?: (item: any, index?: number) => string // 鍵值生成函數
): void
  • dataSource:IDataSource

    LazyForEach數據源,需要開發者實現相關接口

  • itemGenerator:(item: any, index: number) => void

    子組件生成函數,為數組中的每一個數據項創建一個子組件。

  • keyGenerator: (item: any, index: number) => string

    鍵值生成函數,用于給數據源中的每一個數據項生成唯一且固定的鍵值。修改數據源中的一個數據項若不影響其生成的鍵值,則對應組件不會被更新,否則此處組件就會被重建更新。keyGenerator參數是可選的,但是,為了使開發框架能夠更好地識別數組更改并正確更新組件,建議提供

實現IDataSource接口

interface IDataSource {totalCount(): number; // 獲得數據總數getData(index: number): Object; // 獲取索引值對應的數據registerDataChangeListener(listener: DataChangeListener): void; // 注冊數據改變的監聽器unregisterDataChangeListener(listener: DataChangeListener): void; // 注銷數據改變的監聽器
}

DataChangeListener接口

interface DataChangeListener {onDataReloaded(): void; // 重新加載數據完成后調用onDataAdded(index: number): void; // 添加數據完成后調用onDataMoved(from: number, to: number): void; // 數據移動起始位置與數據移動目標位置交換完成后調用onDataDeleted(index: number): void; // 刪除數據完成后調用onDataChanged(index: number): void; // 改變數據完成后調用onDataAdd(index: number): void; // 添加數據完成后調用onDataMove(from: number, to: number): void; // 數據移動起始位置與數據移動目標位置交換完成后調用onDataDelete(index: number): void; // 刪除數據完成后調用onDataChange(index: number): void; // 改變數據完成后調用
}

創建LazyForEach

首次渲染

在LazyForEach首次渲染時,會根據上述鍵值生成規則為數據源的每個數組項生成唯一鍵值并創建相應的組件。

局部代碼如下:

class MyDataSource extends BasicDataSource {private dataArray: string[] = [];public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i <= 20; i++) {this.data.pushData(`Hello ${i}`);}}build() {List({ space: 3 }) { // 必須在容器組件內LazyForEach(this.data, (item: string) => {ListItem() {Row() {Text(item).fontSize(50).onAppear(() => {console.info(`appear: ${item}`);})}.margin({ left: 10, right: 10 })}}, (item: string) => item) // 生成唯一鍵值}.cachedCount(5) // 設置顯示區域外上下預加載布局}
}

渲染結果如圖

在這里插入圖片描述

非首次渲染

當LazyForEach數據源發生變化,需要再次渲染時,開發者應根據數據源的變化情況調用listener對應的接口,通知LazyForEach做相應的更新。

局部代碼如下:

class MyDataSource extends BasicDataSource {private dataArray: string[] = [];public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);this.notifyDataAdd(this.dataArray.length - 1);}
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i <= 20; i++) {this.data.pushData(`Hello ${i}`);}}build() {List({ space: 3 }) {LazyForEach(this.data, (item: string) => {ListItem() {Row() {Text(item).fontSize(50).onAppear(() => {console.info(`appear: ${item}`);})}.margin({ left: 10, right: 10 })}.onClick(() => {// 點擊追加子組件this.data.pushData(`Hello ${this.data.totalCount()}`);})}, (item: string) => item)}.cachedCount(5)}
}

渲染結果如圖:
在這里插入圖片描述

LazyForEach之前:先實現IDataSource接口

// 實現IDataSource接口,用于管理listener監聽,以及通知LazyForEach數據更新
class BasicDataSource implements IDataSource {private listeners: DataChangeListener[] = [];private originDataArray: string[] = [];public totalCount(): number {return this.originDataArray.length;}public getData(index: number): string {return this.originDataArray[index];}// 該方法為框架側調用,為LazyForEach組件向其數據源處添加listener監聽registerDataChangeListener(listener: DataChangeListener): void {if (this.listeners.indexOf(listener) < 0) {console.info('add listener');this.listeners.push(listener);}}// 該方法為框架側調用,為對應的LazyForEach組件在數據源處去除listener監聽unregisterDataChangeListener(listener: DataChangeListener): void {const pos = this.listeners.indexOf(listener);if (pos >= 0) {console.info('remove listener');this.listeners.splice(pos, 1);}}// 通知LazyForEach組件需要重載所有子組件notifyDataReload(): void {this.listeners.forEach(listener => {listener.onDataReloaded();});}// 通知LazyForEach組件需要在index對應索引處添加子組件notifyDataAdd(index: number): void {this.listeners.forEach(listener => {listener.onDataAdd(index);// 寫法2:listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]);});}// 通知LazyForEach組件在index對應索引處數據有變化,需要重建該子組件notifyDataChange(index: number): void {this.listeners.forEach(listener => {listener.onDataChange(index);// 寫法2:listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]);});}// 通知LazyForEach組件需要在index對應索引處刪除該子組件notifyDataDelete(index: number): void {this.listeners.forEach(listener => {listener.onDataDelete(index);// 寫法2:listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]);});}// 通知LazyForEach組件將from索引和to索引處的子組件進行交換notifyDataMove(from: number, to: number): void {this.listeners.forEach(listener => {listener.onDataMove(from, to);// 寫法2:listener.onDatasetChange(//         [{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]);});}notifyDatasetChange(operations: DataOperation[]): void {this.listeners.forEach(listener => {listener.onDatasetChange(operations);});}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93443.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93443.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93443.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態規劃:從入門到精通

本文全章節一共一萬七千多字&#xff0c;詳細介紹動態規劃基礎與進階技巧&#xff0c;全篇以代碼為主&#xff0c;認真讀完理解&#xff0c;你對動態規劃的理解一定會有一個質的飛躍。一、動態規劃簡介: 動態規劃&#xff08;Dynamic Programming&#xff0c;簡稱DP&…

八股訓練營 40 天心得:一場結束,也是一場新的開始

八股訓練營 40 天心得&#xff1a;一場結束&#xff0c;也是一場新的開始 感謝卡哥的訓練營組織卡碼筆記&#xff0c;對即將參加秋招的我們幫助了很多&#xff0c;感謝卡哥的開源代碼隨想錄代碼隨想錄 四十天前&#xff0c;我帶著一顆不安卻堅定的心&#xff0c;踏入了這場“…

STM32系統定時器(SysTick)詳解:從原理到實戰的精確延時與任務調度

前言&#xff1a;為什么SysTick是嵌入式開發的"瑞士軍刀"&#xff1f; 在STM32開發中&#xff0c;我們經常需要精確的延時功能&#xff08;如毫秒級延時控制LED閃爍&#xff09;或周期性任務調度&#xff08;如定時采集傳感器數據&#xff09;。實現這些功能的方式有…

【微信小程序】12、生物認證能力

1、生物認證 生物認證 是一種基于個體獨特生理或行為特征進行身份驗證的技術,廣泛應用于安全、金融、醫療等領域。 小程序目前暫時只支持指紋識別認證。 2、查詢支持的生物認證方式 獲取本機支持的 SOTER 生物認證方式&#xff0c;文檔 onLoad(options) {wx.checkIsSuppor…

高級機器學習

機器學習常見方法涉及方法&#xff1a;2.半監督學習3.無監督學習4.度量學習5.遷移學習6.多示例多標記學習7.在線學習8.元學習9.聯邦學習10.強化學習11.概率圖模型獨立同分布獨立指的是&#xff0c;樣本集包括訓練集測試集的任意兩個樣本之間都是不相關的。在表示樣本的特征確定…

Chrome 提示 “此擴展程序不再受支持”(MacOS/Windows)

原因 最新 Chrome 使用 Manifest V3, 并在新版瀏覽器中 停止 V2 支持 處理方法 MacOS 新建一個后綴為 .mobileconfig 的文件, 內容參考 <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN&…

C++20協程實戰:高效網絡庫、手機終端、多媒體開發開發指南

基于C++協程和事件循環的網絡庫 以下是基于C++協程和事件循環的網絡庫實例,涵蓋常見場景和功能實現。示例基于libuv、Boost.Asio或自定義事件循環,結合C++20協程(如std::coroutine)或其他協程庫(如cppcoro)實現。 基礎TCP服務器 #include <cppcoro/task.hpp> #in…

數據庫4.0

索引 事務 JDBC~ 目錄 一、MySQL索引 1.0 概述 2.0 相關操作 3.0 注意 4.0 索引背后的原理的理解 二、 事務 1.0 原子性 2.0 隔離性 (1)并發執行 (2) 出現的問題 3.0 使用 三、JDBC編程 1.0 概述 2.0 如何下載驅動包 3.0 jar如何引入到項目之中 4.0 jdbc…

HarmonyOS-ArkUI Web控件基礎鋪墊6--TCP協議- 流量控制算法與擁塞控制算法

HarmonyOS-ArkUI Web控件基礎鋪墊1-HTTP協議-數據包內容-CSDN博客 HarmonyOS-ArkUI Web控件基礎鋪墊2-DNS解析-CSDN博客 HarmonyOS-ArkUI Web控件基礎鋪墊3--TCP協議- 從規則本質到三次握手-CSDN博客 HarmonyOS-ArkUI Web控件基礎鋪墊4--TCP協議- 斷聯-四次揮手解析-CSDN博客…

Dify 從入門到精通(2/100 篇):Dify 的核心組件 —— 從節點到 RAG 管道

Dify 的核心組件&#xff1a;從節點到 RAG 管道 引言 在 Dify 博客系列&#xff1a;從入門到精通&#xff08;100 篇&#xff09; 的第一篇《Dify 究竟是什么&#xff1f;真能開啟低代碼 AI 應用開發的未來&#xff1f;》中&#xff0c;我們全面介紹了 Dify 的定位、核心特點…

在線培訓、遠程示教——醫療器械行業的直播解決方案

文章目錄前言一、醫療器械直播應用的兩大核心場景二、直播平臺在醫療場景中的關鍵技術支持點三、典型功能實現原理總結前言 醫療器械行業對“培訓”和“示教”的專業性要求極高&#xff0c;傳統的線下模式常因時間、空間、人員成本等受限而效率低下。而隨著高清低延遲視頻技術…

Mqttnet的MqttClientTlsOptions.CertificateValidationHandler詳解

MqttClientTlsOptions.CertificateValidationHandler 是 MQTTnet 庫中用于自定義 TLS 證書驗證邏輯的關鍵回調函數。在 MQTT 客戶端與服務器建立 TLS 連接時&#xff0c;該回調允許你覆蓋默認的證書驗證流程&#xff0c;實現自定義的安全策略。核心作用當 MQTT 客戶端通過 TLS …

【圖像噪點消除】——圖像預處理(OpenCV)

目錄 1 均值濾波 2 方框濾波 3 高斯濾波 4 中值濾波 5 雙邊濾波 6 小結 噪聲&#xff1a;圖像中的一些干擾因素。通常是由于圖像采集設備、傳輸信道等因素造成的&#xff0c;表現為圖像中隨機的亮度。常見的噪聲類型有高斯噪聲和椒鹽噪聲。高斯噪聲是一種分布符合正態分布…

Vulnhub napping-1.0.1靶機滲透攻略詳解

一、下載靶機 下載地址&#xff1a;https://download.vulnhub.com/napping/napping-1.0.1.ova 下載好后使用VM打開&#xff0c;將網絡配置模式改為net&#xff0c;防止橋接其他主機干擾&#xff08;橋接Mac地址也可確定主機&#xff09;。 二、發現主機 使用nmap掃描沒有相應…

Kubernetes自動擴容方案

Kubernetes 自動擴容可以概括為 “三層六類”&#xff1a;層級類型觸發維度官方/社區方案一句話說明Pod 級HPACPU / 內存 / 自定義 / 外部指標內置副本數橫向擴縮&#xff0c;最常用VPACPU / 內存社區組件單 Pod 資源豎向擴縮&#xff0c;不改副本數KEDA任意事件&#xff08;隊…

linux命令ps的實際應用

ps&#xff08;Process Status&#xff09;是 ?Linux/Unix 系統中最核心的進程管理工具&#xff0c;用于實時抓取系統進程快照。它直接讀取 /proc 文件系統&#xff0c;不持續監控進程&#xff08;區別于 top&#xff09;&#xff0c;但可通過參數組合實現精準進程診斷。下面從…

深入理解C語言:詳解直接插入排序的實現與優化

目錄 引言 一、直接插入排序的相關概念 1.1、基本概念 1.2、直接插入排序過程詳解 二、代碼實現 三、時間復雜度 四、希爾排序 4.1、希爾排序的陳述 4.2、代碼實現 4.3、時間復雜度 結語 引言 在計算機科學的世界里&#xff0c;排序算法是基礎且重要的組成部分。它們…

【DRAM存儲器五十五】LPDDR5介紹--command bus training

??個人主頁:highman110 ??作者簡介:一名硬件工程師,持續學習,不斷記錄,保持思考,輸出干貨內容 參考資料:《某LPDDR5數據手冊》 、《JESD209-5A》 在為高頻或中頻操作啟用ODT之前,必須對L

一道曾經百度面試題

&#x1f680;個人主頁&#xff1a;BabyZZの秘密日記 &#x1f4d6;收入專欄&#xff1a;C語言 &#x1f30d;文章目入1. 題目重現2. 大小端到底在比什么&#xff1f;3. 解法一&#xff1a;聯合體&#xff08;union&#xff09;為什么一行就夠&#xff1f;使用示例4. 解法二&am…

VIKOR(Multi-criteria Optimization and Compromise Solution)簡介與簡單示例

前言 提醒&#xff1a; 文章內容為方便作者自己后日復習與查閱而進行的書寫與發布&#xff0c;其中引用內容都會使用鏈接表明出處&#xff08;如有侵權問題&#xff0c;請及時聯系&#xff09;。 其中內容多為一次書寫&#xff0c;缺少檢查與訂正&#xff0c;如有問題或其他拓展…