网站首页 > 精选文章 / 正文
深入理解 ArkUI - 组件生命周期
组件生命周期
官网对生命周期做了初步介绍. 生命周期流程如下图所示,下图展示的是被@Entry装饰的组件(页面)生命周期。
页面级组件(@Entry修饰)
创建新工程在编译文件build/default/cache/default/default@CompileArkTS/esmodule/debug/entry/src/main/ets/pages/Index.ts中通过registerNamedRoute(() => new ObscuredExample(undefined, {}), "", { bundleName: "com.ohos.test", moduleName: "entry", pagePath: "pages/Index", pageFullPath: "entry/src/main/ets/pages/Index", integratedHsp: "false" });函数创建根组件ObscuredExample。 组件继承关系:ObscuredExample继承自ViewPU,ViewPU继承自PUV2ViewBase,PUV2ViewBase继承自NativeViewPartialUpdate,ObscuredExample最终创建NativeViewPartialUpdate类型的对象。
前后端对象绑定
Ark虚拟机通过JSClass<JSViewPartialUpdate>::Declare("NativeViewPartialUpdate")将前端NativeViewPartialUpdate对象和后端JSViewPartialUpdate对象绑定。
frameworks/bridge/declarative_frontend/jsview/js_view.cpp
void JSViewPartialUpdate::JSBind(BindingTarget object)
{
JSClass<JSViewPartialUpdate>::Declare("NativeViewPartialUpdate");
MethodOptions opt = MethodOptions::NONE;
JSClass<JSViewPartialUpdate>::StaticMethod("create", &JSViewPartialUpdate::Create, opt);
JSClass<JSViewPartialUpdate>::StaticMethod("createRecycle", &JSViewPartialUpdate::CreateRecycle, opt);
...
JSClass<JSViewPartialUpdate>::InheritAndBind<JSViewAbstract>(object, ConstructorCallback, DestructorCallback);
}
JSViewPartialUpdate对象与CustomNode对象绑定
后端的自定义组件是以CustomNode对象管理,如何绑定的?
- 创建后端JSViewPartialUpdate对象,并绑定ViewFunctions对象。ViewFunctions对象是后端调用前端函数的封装,其中包含组件生命周期回调。
- CreateViewNode函数通过view_partial_update_model_ng.cpp创建CustomNodeBase对象并建立与ViewFunctions的绑定关系。这样封装主要是为了拆分新老ArkUI框架。
RefPtr<AceType> ViewPartialUpdateModelNG::CreateNode(NodeInfoPU&& info)
{
// create component, return new something, need to set proper ID
auto viewId = NG::ViewStackProcessor::GetInstance()->ClaimNodeId();
ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", info.jsViewName.c_str(), viewId);
...
RefPtr<NG::CustomNodeBase> customNode;
...
customNode = NG::CustomNode::CreateCustomNode(viewId, key);
if (info.updateNodeFunc) {
info.updateNodeFunc(customNode);
}
customNode->SetAppearFunction(std::move(info.appearFunc));
customNode->SetDidBuildFunction(std::move(info.didBuildFunc));
auto renderFunc = [renderFunction = std::move(info.renderFunc)]() -> RefPtr<UINode> {
auto node = renderFunction();
return AceType::DynamicCast<UINode>(node);
};
customNode->SetRenderFunction(std::move(renderFunc));
customNode->SetUpdateFunction(std::move(info.updateFunc));
customNode->SetDestroyFunction(std::move(info.removeFunc));
...
return customNode;
}
页面级组件生命周期绑定
AceContainer初始化会注册生命周期绑定函数UpdateRootComponent给pageRouterManager。当页面加载时,通过pageRouterManager将生命周期与PageNode绑定。
frameworks/bridge/declarative_frontend/engine/jsi/jsi_view_register_impl_ng.cpp
void UpdateRootComponent(const EcmaVM* vm, const panda::Local<panda::ObjectRef>& obj)
{
...
pageRootNode->MountToParent(pageNode);
// update page life cycle function.
auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
CHECK_NULL_VOID(pagePattern);
// Register RenderDone callback to jsView so that js view can notify pagePattern the render function has been
// finish. The onPageShow life cycle must be after the InitialRender function execution.
view->RegisterRenderDoneCallback([weak = AceType::WeakClaim(AceType::RawPtr(pagePattern))]() {
auto pagePattern = weak.Upgrade();
CHECK_NULL_VOID(pagePattern);
pagePattern->MarkRenderDone();
});
pagePattern->SetOnPageShow([weak = Referenced::WeakClaim(view)]() {
auto view = weak.Upgrade();
if (view) {
view->FireOnShow();
}
});
pagePattern->SetOnPageHide([weak = Referenced::WeakClaim(view)]() {
auto view = weak.Upgrade();
if (view) {
view->FireOnHide();
}
});
pagePattern->SetOnBackPressed([weak = Referenced::WeakClaim(view)]() {
auto view = weak.Upgrade();
if (view) {
return view->FireOnBackPress();
}
return false;
});
auto customNode = AceType::DynamicCast<NG::CustomNodeBase>(pageRootNode);
pagePattern->SetPageTransitionFunc(
[weakCustom = WeakPtr<NG::CustomNodeBase>(customNode), weakPage = WeakPtr<NG::FrameNode>(pageNode)]() {
auto custom = weakCustom.Upgrade();
auto page = weakPage.Upgrade();
if (custom && page) {
NG::ScopedViewStackProcessor scopedViewStackProcessor;
NG::ViewStackProcessor::GetInstance()->SetPageNode(page);
custom->CallPageTransitionFunction();
NG::ViewStackProcessor::GetInstance()->SetPageNode(nullptr);
}
});
}
aboutToAppear、build、onDidBuild
前文已经分析首页通过页面组件通过router.pushUrl方式加载,主要流程在StageManager::PushPage函数。
frameworks/core/components_ng/pattern/stage/stage_manager.cpp
bool StageManager::PushPage(const RefPtr<FrameNode>& node, bool needHideLast, bool needTransition)
{
...
// mount to parent and mark build render tree.
node->MountToParent(stageNode_);
// then build the total child. Build will trigger page create and onAboutToAppear
node->Build(nullptr);
// fire new lifecycle
if (hidePageNode && needHideLast && isNewLifecycle) {
FirePageHide(hidePageNode, needTransition ? PageTransitionType::EXIT_PUSH : PageTransitionType::NONE);
}
stageNode_->RebuildRenderContextTree();
FirePageShow(node, needTransition ?
...
stageNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
return true;
}
- 1. 通过MountToParent构建组件父子依赖,前文已讲述。
- 2. 组件Build,由于是自定义组件,这里的node是CustomNode类型。
- 3. 页面生命周期onPageShow触发
- 4. 标脏请求Vsync,完成页面渲染
Render函数依次触发OnAppear、BuildItem、DidBuild生命周期回调.
void CustomNode::Render()
{
// NOTE: this function will be re-enter, we need backup needMarkParent_ first and restore it later.
bool needMarkParentBak = needMarkParent_;
needMarkParent_ = false;
if (renderFunction_) {
RenderFunction renderFunction = nullptr;
std::swap(renderFunction, renderFunction_);
{
ACE_SCOPED_TRACE("CustomNode:OnAppear");
FireOnAppear();
}
{
COMPONENT_CREATION_DURATION();
ACE_SCOPED_TRACE("CustomNode:BuildItem [%s][self:%d][parent:%d]", GetJSViewName().c_str(), GetId(),
GetParent() ? GetParent()->GetId() : 0);
// first create child node and wrapper.
ScopedViewStackProcessor scopedViewStackProcessor;
auto parent = GetParent();
bool parentNeedExportTexture = parent ? parent->IsNeedExportTexture() : false;
ViewStackProcessor::GetInstance()->SetIsExportTexture(parentNeedExportTexture || IsNeedExportTexture());
auto child = renderFunction();
if (child) {
child->MountToParent(Claim(this));
}
}
{
ACE_SCOPED_TRACE("CustomNode::DidBuild");
FireDidBuild();
}
}
{
FireRecycleRenderFunc();
}
needMarkParent_ = needMarkParentBak;
}
onPageShow
组件创建完成后在FirePageShow函数触发页面OnPageShow。
onPageHide
当页面且后台,切换等操作触发页面OnPageHide
frameworks/core/components_ng/pattern/stage/stage_manager.cpp
bool StageManager::PopPage(const RefPtr<FrameNode>& inPage, bool needShowNext, bool needTransition)
{
...
FirePageHide(pageNode, needTransition ? PageTransitionType::EXIT_POP : PageTransitionType::NONE);
...
stageNode_->RemoveChild(pageNode);
pipeline->RequestFrame();
return true;
}
aboutToDisapear、aboutToDestory
stageNode_->RemoveChild会将组件从组件树移除然后组件析构。自定义组件在后端是CustomNode对象继承自CustomNodeBase。
CustomNodeBase::~CustomNodeBase()
{
RecycleManager::Erase(recycleInfo_.elemtId);
// appearFunc_ & destroyFunc_ should be executed in pairs
if (!executeFireOnAppear_ && appearFunc_) {
appearFunc_();
if (didBuildFunc_) {
didBuildFunc_();
}
}
if (destroyFunc_) {
ACE_SCOPED_TRACE("CustomNodeBase:Destroy [%s]", GetJSViewName().c_str());
destroyFunc_();
}
}
destroyFunc_函数与removeFunction函数绑定
auto removeFunction = [weak = AceType::WeakClaim(this)]() -> void {
auto jsView = weak.Upgrade();
CHECK_NULL_VOID(jsView);
ContainerScope scope(jsView->GetInstanceId());
jsView->Destroy(nullptr);
jsView->viewNode_.Reset();
};
最终借助jsViewFunction_这个桥梁执行到前端的aboutToDisappear和aboutToBeDelete。
void JSViewPartialUpdate::Destroy(JSView* parentCustomView)
{
if (jsViewFunction_ == nullptr) {
// already called Destroy before
return;
}
{
ACE_SCORING_EVENT("Component[" + viewId_ + "].Disappear");
jsViewFunction_->ExecuteDisappear();
}
{
ACE_SCORING_EVENT("Component[" + viewId_ + "].AboutToBeDeleted");
jsViewFunction_->ExecuteAboutToBeDeleted();
}
pendingUpdateTasks_.clear();
jsViewFunction_->Destroy();
jsViewFunction_.Reset();
// release reference to JS view object, and allow GC, calls DestructorCallback
jsViewObject_.Reset();
}
详细流程图如下:
自定义组件(@Component修饰)
除了上述通过应用启动、router.pushUrl等方式触发页面加载,If分支切换、ForEach数组变更、LazyForEach触发的预加载或者Key值变化都会触发非页面级组件的删除和重建。 删除:触发aboutToDisappear、aboutToBeDelete 重建: 触发OnAppear、BuildItem、DidBuild生命周期回调
基础组件
当前基础组件的生命周期包含onAppear、onDisAppear、onAttach、onDetach,通过属性的方式注册到后端的EventHub中保存。 当组件上树时触发onAttach、onAppear。
void FrameNode::OnAttachToMainTree(bool recursive)
{
TriggerRsProfilerNodeMountCallbackIfExist();
eventHub_->FireOnAttach();
eventHub_->FireOnAppear();
...
}
eventHub_->FireOnAttach在挂树后立即执行
void EventHub::FireOnAttach()
{
if (onAttach_) {
auto onAttach = onAttach_;
onAttach();
}
}
eventHub_->FireOnAppear在Vsync消息后执行
void EventHub::FireOnAppear()
{
if (onAppear_ || onJSFrameNodeAppear_) {
auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
CHECK_NULL_VOID(pipeline);
auto taskScheduler = pipeline->GetTaskExecutor();
CHECK_NULL_VOID(taskScheduler);
taskScheduler->PostTask(
[weak = WeakClaim(this)]() {
auto eventHub = weak.Upgrade();
CHECK_NULL_VOID(eventHub);
if (eventHub->onAppear_) {
// callback may be overwritten in its invoke so we copy it first
auto onAppear = eventHub->onAppear_;
onAppear();
}
if (eventHub->onJSFrameNodeAppear_) {
// callback may be overwritten in its invoke so we copy it first
auto onJSFrameNodeAppear = eventHub->onJSFrameNodeAppear_;
onJSFrameNodeAppear();
}
},
TaskExecutor::TaskType::UI, "ArkUIFrameNodeAppearEvent");
}
}
组件下树触发onDetach、onDisAppear。
void FrameNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
{
...
eventHub_->OnDetachClear();
...
}
void EventHub::OnDetachClear()
{
FireOnDetach();
FireOnDisappear();
ClearStateStyle();
}
FireOnDetach在下树后立即执行
void EventHub::FireOnDetach()
{
if (onDetach_) {
auto onDetach = onDetach_;
onDetach();
}
}
FireOnDisappear在下树后立即执行
void EventHub::FireOnDisappear()
{
if (onDisappear_) {
// callback may be overwritten in its invoke so we copy it first
auto onDisappear = onDisappear_;
onDisappear();
}
if (onJSFrameNodeDisappear_) {
// callback may be overwritten in its invoke so we copy it first
auto onJSFrameNodeDisappear = onJSFrameNodeDisappear_;
onJSFrameNodeDisappear();
}
}
总结
写个实例测试下,依次执行启动,点击Button按钮,且后台,执行结果如下:
@Entry
@Component
struct ObscuredExample {
onPageShow(): void {
console.log("LifeCycle Entry onPageShow");
}
aboutToAppear(): void {
console.log("LifeCycle Entry aboutToAppear");
}
aboutToDisappear(): void {
console.log("LifeCycle Entry aboutToDisappear");
}
onPageHide(): void {
console.log("LifeCycle Entry onPageHide");
}
@State isShow: boolean = true
build() {
Row() {
Column() {
Button()
.onClick(() => {
this.isShow = !this.isShow
})
if (this.isShow) {
My()
.width('100%')
.height('100%')
.onAppear(() => {
console.log("LifeCycle Component onAppear");
})
.onAttach(() => {
console.log("LifeCycle Component onAttach");
})
.onDetach(() => {
console.log("LifeCycle Component onDetach");
})
.onDisAppear(() => {
console.log("LifeCycle Component onDisAppear");
})
}
}
.width('100%')
}
.height('100%')
}
}
Tags:js生命周期
猜你喜欢
- 2024-12-27 为什么都在用Node.js?Node.js到底是什么?
- 2024-12-27 2024年你应该使用的15个JavaScript库
- 2024-12-27 分享 JavaScript 2024 的 6 个新功能
- 2024-12-27 JavaScript知识点——详细的Cookie总结
- 2024-12-27 前端基础进阶(一):内存空间详细图解
- 2024-12-27 p5.js 视频播放指南 p5.js 教程
- 2024-12-27 React生命周期详解(新版) react生命周期setstate
- 2024-12-27 2024年 React.js快速入门备忘清单,让你轻松掌握 React.js
- 2024-12-27 10天学会React——属性,状态,事件,生命周期
- 2024-12-27 js和vue实现时分秒倒计时的方法 vue写倒计时一分钟