页面和自定义组件生命周期
先明确自定义组件和页面的关系:
-
自定义组件:@Component装饰的UI单元,可以组合多个系统组件实现U的复用。
-
页面:即应用的UI页面。可以由一个或者多个自定义组件组成,@Entry装饰的自定义组件为贞面的入口组件,即页面的根节点,一个页面有且仅能有一个@Ertry。只有被@Entry装饰的组件才可以调用页面的生命周期。“页面生命周期,即被@Entry装饰的组件生命周期,提供以下生命周期接口
-
onPageShow:页面每次显示时触发。
-
onPageHide:页面每次隐藏时触发一次。
-
onBackPress:当用户点击返回按钮时触发。
组件生命周期,即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:
-
aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
-
aboutToDisappear:在自定义组件即将析构销毁时执行。
-
生命周期流程如下图所示,下图展示的是被@Entry装饰的组件(首页)生命周期。
需要注意的是,部分生命周期回调函数仅对@Entry修的自定义组件生效,它们分别是:onpageShow、onpageHide、onBackpress。根据上面的流程图,我们从自定义组件的初始创建、重新渲染和删除来详细解释。
自定义组件的创建和渲染流程
-
自定义组件的创建:自定义组件的实例由ArkuI框架创建。
-
初始化自定义组件的成员变量:通过本地默认值或者构造方法传递参数来初始化自定义组件的成员变量,初始化顺序为成员变量的定义顺序。
-
如果开发者定义了 aboutToAppear,则执行 aboutToappear 方法。
-
在首次渲染的时候,执行build方法染系统组件,如果子组件为自定义组件,则创建自定义组件的实例。在执行build()函数的过程中,框架会观察每个状态变量的读取状态,将保存两个map
a.状态变量->UI组件(包括ForEach和if)。 b.UI 组件 ->此组件的更新函数,即一个 lambda 方法,作为 build()函数的子集,创建对应的UI组件并执行其属性方法,示意如下。
当应用在后台启动时,此时应用进程并没有销毁,所以仅需要执行enpageshow
自定义组件重新渲染
当事件句柄被触发(比如设置了点击事件,即触发点击事件)改变了状态变量时,或晋Localstorage/appStorage 中的属性更改,并导致绑定的状态变量更改其值时:
-
框架观察到了变化,将启动重新渲染。
-
根据框架持有的两个map(自定义组件的创建和渲染流程中第4步),框架可以知道该状态变量管理了哪些UI组件,以及这些UI组件对应的更新函数。执行这些UI 组件的更新函数,实现最小化更新。
自定义组件的删除
如果if组件的分支改变,或者ForEach 循环渲染中数组的个数改变,组件将被删除
-
在删除组件之前,将调用其aboutToDisappear生命周期函数,标记该节点将要被销毁。ArkUI的节点删除机制是:后端节点直接从组件树上摘下,后端节点被销毁,对前端节点解引用,当前端节点已经没有引用时,将被JS虚拟机垃圾回收。
-
自定义组件和它的变量将被删除,如果其有同步的变量,比如@Link、@Prop、@StorageLink,将从同步源上取消注册。
不建议在生命周期 aboutToDisappear内使用async await,如果在生命周期的aboutToDisappear使用异步操作(Promise或者回调方法),自定义组件将被保留在Promise的闭包中,直到回调方法被执行完,这个行为阻止了自定义组件的垃圾回收
aboutToAppear( )函数
探究组件什么时候被创建的回调函数
aboutToDisAppear( )函数
探究组件什么时候被销毁的回调函数
onPageShow( )函数
在组件显示的时候自动进行回调
onpageHide( )函数
在组件隐藏的时候自动进行回调
onBackPress( )函数
在按钮被点击的时候进行回调
示例代码:
//自定义组件
import FaultLogger from '@ohos.faultLogger'
import router from '@ohos.router'
@Component
struct MyChildComponent {
@State
username: string = "子木"
//组件什么时候被创建的回调函数
aboutToAppear() {
console.info('MychildComponent被创建了')
}
//组件被销毁时候执行的回调函数
aboutToDisappear() {
console.info('MyChildComponent被销毁了')
}
build() {
Column() {
Text(`hello${this.username}`)
.fontSize(50)
.onClick(() => {
this.username = "张三"
})
}
}
}
//入口组件(页面)
@Entry
@Component
struct Test8 {
@State
isShowChild: boolean = true //是否显示自定义组件
//组件什么时候被创建的回调函数
aboutToAppear() {
console.info('test8被创建了')
}
//组件被销毁时候执行的回调函数
aboutToDisappear() {
console.info('test8被销毁了')
}
//在页面显示的时候自动进行回调
onPageShow() {
console.info('test8页面显示了')
}
//在页面隐藏的时候自动进行回调
onPageHide() {
console.info('test8隐藏了')
}
//返回按钮被点击
onBackPress() {
console.info('test8返回按钮点击了')
}
build() {
Column() {
Text(`我的主页面test8`)
.fontSize(40)
.fontWeight(FontWeight.Bold)
//自定义组件
if (this.isShowChild) {
MyChildComponent()
}
//点击一个按钮改变 isShowChild属性为false
Button('删除子组件')
.onClick(() => {
this.isShowChild = false
})
//把当前test8页面隐藏,可以通过跳转到另外一个页面
Button('跳转其他页面')
.onClick(() => {
router.pushUrl({ url: "pages/index.ets" })
})
}
}
}
点击运行预览器之后
还没有进行点击操作我们就可以看到
当我点击删除子组件的时候
当我们点击 跳转到其他页面 通过设置路由即可显示,并且触发onpageHide( )隐藏函数。