鸿蒙开发笔记(三):页面和自定义组件生命周期

news2024/11/20 6:29:55

先明确自定义组件和页面的关系:

  • 自定义组件:@Component装饰的UI单元,可以组合多个系统组件实现UI的复用。

  • 页面:即应用的UI页面。可以由一个或者多个自定义组件组成,@Entry装饰的自定义组件为页面的入口组件,即页面的根节点,一个页面有且仅能有一个@Entry。只有被@Entry装饰的组件才可以调用页面的生命周期。

页面生命周期,即被@Entry装饰的组件生命周期,提供以下生命周期接口:

  • onPageShow:页面每次显示时触发。
  • onPageHide:页面每次隐藏时触发一次。
  • onBackPress:当用户点击返回按钮时触发。

组件生命周期,即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:

  • aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。

  • aboutToDisappear:在自定义组件即将析构销毁时执行。

生命周期流程如下图所示,下图展示的是被@Entry装饰的组件(首页)生命周期。
在这里插入图片描述
根据上面的流程图,我们从自定义组件的初始创建、重新渲染和删除来详细解释。

1. 自定义组件的创建和渲染流程

  1. 自定义组件的创建:自定义组件的实例由ArkUI框架创建。

  2. 初始化自定义组件的成员变量:通过本地默认值或者构造方法传递参数来初始化自定义组件的成员变量,初始化顺序为成员变量的定义顺序。

  3. 如果开发者定义了aboutToAppear,则执行aboutToAppear方法。

  4. 在首次渲染的时候,执行build方法渲染系统组件,如果子组件为自定义组件,则创建自定义组件的实例。在执行build()函数的过程中,框架会观察每个状态变量的读取状态,将保存两个map:

    a. 状态变量 -> UI组件(包括ForEach和if)。

    b. UI组件 -> 此组件的更新函数,即一个lambda方法,作为build()函数的子集,创建对应的UI组件并执行其属性方法,示意如下。

build() {
  ...
  this.observeComponentCreation(() => {
    Button.create();
  })

  this.observeComponentCreation(() => {
    Text.create();
  })
  ...
}

当应用在后台启动时,此时应用进程并没有销毁,所以仅需要执行onPageShow。

2. 自定义组件重新渲染

当事件句柄被触发(比如设置了点击事件,即触发点击事件)改变了状态变量时,或者LocalStorage / AppStorage中的属性更改,并导致绑定的状态变量更改其值时:

  1. 框架观察到了变化,将启动重新渲染。

  2. 根据框架持有的两个map(自定义组件的创建和渲染流程中第4步),框架可以知道该状态变量管理了哪些UI组件,以及这些UI组件对应的更新函数。执行这些UI组件的更新函数,实现最小化更新。

3. 自定义组件的删除

如果if组件的分支改变,或者ForEach循环渲染中数组的个数改变,组件将被删除:

  1. 在删除组件之前,将调用其aboutToDisappear生命周期函数,标记着该节点将要被销毁。ArkUI的节点删除机制是:后端节点直接从组件树上摘下,后端节点被销毁,对前端节点解引用,当前端节点已经没有引用时,将被JS虚拟机垃圾回收。

  2. 自定义组件和它的变量将被删除,如果其有同步的变量,比如@Link、@Prop、@StorageLink,将从同步源上取消注册。

不建议在生命周期aboutToDisappear内使用async await,如果在生命周期的aboutToDisappear使用异步操作(Promise或者回调方法),自定义组件将被保留在Promise的闭包中,直到回调方法被执行完,这个行为阻止了自定义组件的垃圾回收。

以下示例展示了生命周期的调用时机:

// Index.ets
import router from '@ohos.router';

@Entry
@Component
struct MyComponent {
  @State showChild: boolean = true;

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onBackPress() {
    console.info('Index onBackPress');
  }

  // 组件生命周期
  aboutToAppear() {
    console.info('MyComponent aboutToAppear');
  }

  // 组件生命周期
  aboutToDisappear() {
    console.info('MyComponent aboutToDisappear');
  }

  build() {
    Column() {
      // this.showChild为true,创建Child子组件,执行Child aboutToAppear
      if (this.showChild) {
        Child()
      }
      // this.showChild为false,删除Child子组件,执行Child aboutToDisappear
      Button('create or delete Child').onClick(() => {
        this.showChild = false;
      })
      // push到Page2页面,执行onPageHide
      Button('push to next page')
        .onClick(() => {
          router.pushUrl({ url: 'pages/Page2' });
        })
    }

  }
}

@Component
struct Child {
  @State title: string = 'Hello World';
  // 组件生命周期
  aboutToDisappear() {
    console.info('[lifeCycle] Child aboutToDisappear')
  }
  // 组件生命周期
  aboutToAppear() {
    console.info('[lifeCycle] Child aboutToAppear')
  }

  build() {
    Text(this.title).fontSize(50).onClick(() => {
      this.title = 'Hello ArkUI';
    })
  }
}

以上示例中,Index页面包含两个自定义组件,一个是被@Entry装饰的MyComponent,也是页面的入口组件,即页面的根节点;一个是Child,是MyComponent的子组件。只有@Entry装饰的节点才可以生效页面的生命周期方法,所以MyComponent中声明了当前Index页面的页面生命周期函数。MyComponent和其子组件Child也同时也声明了组件的生命周期函数。

  • 应用冷启动的初始化流程为:MyComponent aboutToAppear --> MyComponent build --> Child aboutToAppear --> Child build --> Child build执行完毕 --> MyComponent build执行完毕 --> Index onPageShow。

  • 点击“delete Child”,if绑定的this.showChild变成false,删除Child组件,会执行Child aboutToDisappear方法。

  • 点击“push to next page”,调用router.pushUrl接口,跳转到另外一个页面,当前Index页面隐藏,执行页面生命周期Index onPageHide。此处调用的是router.pushUrl接口,Index页面被隐藏,并没有销毁,所以只调用onPageHide。跳转到新页面后,执行初始化新页面的生命周期的流程。

  • 如果调用的是router.replaceUrl,则当前Index页面被销毁,执行的生命周期流程将变为:Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已经提到,组件的销毁是从组件树上直接摘下子树,所以先调用父组件的aboutToDisappear,再调用子组件的aboutToDisappear,然后执行初始化新页面的生命周期流程。

  • 点击返回按钮,触发页面生命周期Index onBackPress,且触发返回一个页面后会导致当前Index页面被销毁。

  • 最小化应用或者应用进入后台,触发Index onPageHide。当前Index页面没有被销毁,所以并不会执行组件的aboutToDisappear。应用回到前台,执行Index onPageShow。

  • 退出应用,执行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1385593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux网络通信

网络模型 七层模型 四层模型 TCP : 面向连接&#xff0c;可靠的&#xff0c;面向字节流&#xff0c;支持点对点通信。 UDP : 无连接&#xff0c;不可靠&#xff0c;面向数据报文&#xff0c;支持一对一&#xff0c;一对多&#xff0c;多对多。通信原理 常用函数 #include <…

LC 82. 删除排序链表中的重复元素 II

82. 删除排序链表中的重复元素 II 难度&#xff1a; 中等 题目大意&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 提示&#xff1a; 链表中节点数目在范围 [0, 300] 内-…

GIT SourceTree 回滚提交

步骤一&#xff1a; 步骤二&#xff1a; 步骤三&#xff1a; 在终端输入命令&#xff08;位置是项目目录下&#xff09; git push origin feature_mo2.1_r3_zhanx653 -f

#LLMOps##AIGC# Dify_构建本地知识库问答应用-生成Al应用的创新引擎 用于构建助手API和GPT的开源开发平台

github&#xff1a; https://github.com/langgenius/dify/blob/main/README_CN.md 介绍文档&#xff1a;https://docs.dify.ai/getting-started/readme Dify 介绍 Dify 笔记 Dify 是什么&#xff1f; 开源的大语言模型&#xff08;LLM&#xff09;应用开发平台融合了后端即服…

电商服务类指标分析(2)——售后管理模块指标

段时间做了一个电商服务类项目&#xff0c;与业务一起梳理了部分指标&#xff0c;这些指标便于了解电商服务&#xff0c;现在做一个整理和回顾。 电商服务类指标可以分为五大类&#xff0c;涵盖了服务从售前、履约、售后、用户反馈、监控预警这样一条链路的内容。 本篇文章来聊…

React入门 - 02(工程目录结构解析)

本章内容 目录 1 外层“文件”说明2 各个“文件夹”说明 接着上一节的内容&#xff0c;我们继续这一节的内容–工程目录文件解析。打开上一节已经建好的工程 react-demo,详细的来了解一些里面的文件。 1 外层“文件”说明 .gitignore — 当我们使用 git 的时候&#xff0c;希…

统计学习 复习(知识点+习题)

复习资料&#xff1a;https://github.com/RuijieZhu94/StatisticalLearning_USTC 第一章 线性回归 1. From one to two 最小二乘 课后题 有偏/无偏估计 加权最小二乘 2. Regularization 线性回归&#xff08;二维情况&#xff09; 求解有约束优化问题 正则化最小加权二乘…

Web3与环保:区块链如何推动可持续发展

随着气候变化和环境问题日益严峻&#xff0c;社会对可持续发展的需求变得愈发迫切。在这个背景下&#xff0c;Web3技术和区块链崭露头角&#xff0c;成为推动可持续发展的关键力量。本文将深入探讨Web3技术如何与环保理念相结合&#xff0c;引领我们迈向更加可持续的未来。 1. …

Java异常:toString()和getMessage()区别

首先写了两个错误 Controller public class DemoController {RequestMapping("/show1")public String showInfo(){String str null;str.length();return "index";}RequestMapping("/show2")public String showInfo2(){int a 10/0;return &quo…

postman上传文件文件名有黄色图标

问题&#xff1a; 解决方案 步骤一&#xff1a;设置处打开settings 步骤二&#xff1a;打开location&#xff0c;选择文件所在磁盘目录 步骤三&#xff1a;关闭选项框 文件报错问题解决

VS 中调用调试DLL库的方法

前提条件&#xff1a; 1、当前代码是最新的&#xff0c;并且编译成dll的库有程序使用。 2、打开运行dll库的程序。 配置步骤&#xff1a; 1、使用VS打开要调试的dll库项目。 2、点击调试菜单展开调试菜单。 3、点击附加到进程&#xff0c;弹出配置框。 4、在配置框中选…

第十周:CV视觉内容深入(可选)

到这里基本AI需要准备的一些基础内容都已经ready了&#xff0c;我本人是视觉出身&#xff0c;所以还是想走老路子&#xff0c;不花费大量时间去往别的方向走了&#xff0c;所以针对视觉部分的内容我自己会单独拓展补充一些内容&#xff0c;选择性享用即可&#xff0c;欢迎交流&…

使用CLIP和LLM构建多模态RAG系统

在本文中我们将探讨使用开源大型语言多模态模型(Large Language Multi-Modal)构建检索增强生成(RAG)系统。本文的重点是在不依赖LangChain或LLlama index的情况下实现这一目标&#xff0c;这样可以避免更多的框架依赖。 什么是RAG 在人工智能领域&#xff0c;检索增强生成(re…

云端部署与本地部署:哪个最适合您的业务?

云端部署与本地部署&#xff1a;哪个最适合您的业务? 云的广泛采用导致许多供应商将重点从本地解决方案转移到云交付模型&#xff0c;从而引发了一个问题&#xff1a;“哪种方式最适合我的业务?”如果您想知道哪个选项更安全、更方便且更实惠&#xff0c;请探索我们方便的比较…

什么是WhatsApp Business?WhatsApp和WhatsApp Business区别?

什么是WhatsApp Business&#xff1f; WhatsApp Business账号是Meta专为企业设计的WhatsApp账号。不同于消费者层次的应用&#xff0c;WhatsApp Business旨在为企业提供更好的服务支持&#xff0c;方便企业与消费者建立更好的双向沟通渠道。 WhatsApp和WhatsApp Business有什…

CLion、IDEA设置编码为utf-8,防乱码

其实只要是JetBrains的软件都是通用的&#xff0c;下面以IDEA为例 1.设置项目文件编码 2.设置控制台的字符编码

保姆级Arduino开发环境搭建

Arduino&#xff0c;一个易于上手且功能丰富的开源平台&#xff0c;不仅包含了各种型号的Arduino开发板等硬件部分&#xff0c;还囊括了Arduino IDE等软件部分。更重要的是&#xff0c;它还拥有由广大爱好者和专业人员共同搭建和维护的互联网社区和资源&#xff0c;为创客们提供…

C语言经典算法之冒泡排序算法

目录 前言 建议&#xff1a; 简介&#xff1a; 一、代码实现 二、时空复杂度 时间复杂度&#xff1a; 空间复杂度&#xff1a; 总结&#xff1a; 前言 建议&#xff1a; 1.学习算法最重要的是理解算法的每一步&#xff0c;而不是记住算法。 2.建议读者学习算法的时候…

微调您的Embedding模型以最大限度地提高RAG管道中的相关性检索

英文原文地址&#xff1a;https://betterprogramming.pub/fine-tuning-your-embedding-model-to-maximize-relevance-retrieval-in-rag-pipeline-2ea3fa231149 微调您的Embedding模型以最大限度地提高RAG管道中的相关性检索 微调嵌入前后的 NVIDIA SEC 10-K 文件分析 2023 年…

C#灵活控制多线程的状态(开始暂停继续取消)

ManualResetEvent类 ManualResetEvent是一个同步基元&#xff0c;用于在多线程环境中协调线程的执行。它提供了两种状态&#xff1a;终止状态和非终止状态。 在终止状态下&#xff0c;ManualResetEvent允许线程继续执行。而在非终止状态下&#xff0c;ManualResetEvent会阻塞线…