MySQL, Oracle, Linux, 软件架构及大数据技术知识分享平台

网站首页 > 精选文章 / 正文

深入理解 ArkUI - 组件生命周期 组件的生命周期有哪些

2024-12-27 13:41 huorong 精选文章 5 ℃ 0 评论

深入理解 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继承自ViewPUViewPU继承自PUV2ViewBasePUV2ViewBase继承自NativeViewPartialUpdateObscuredExample最终创建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对象管理,如何绑定的?

  1. 创建后端JSViewPartialUpdate对象,并绑定ViewFunctions对象。ViewFunctions对象是后端调用前端函数的封装,其中包含组件生命周期回调。
  2. 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初始化会注册生命周期绑定函数UpdateRootComponentpageRouterManager。当页面加载时,通过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. 1. 通过MountToParent构建组件父子依赖,前文已讲述。
  2. 2. 组件Build,由于是自定义组件,这里的nodeCustomNode类型。
  3. 3. 页面生命周期onPageShow触发
  4. 4. 标脏请求Vsync,完成页面渲染

Render函数依次触发OnAppearBuildItemDidBuild生命周期回调.

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_这个桥梁执行到前端的aboutToDisappearaboutToBeDelete

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值变化都会触发非页面级组件的删除和重建。 删除:触发aboutToDisappearaboutToBeDelete 重建: 触发OnAppearBuildItemDidBuild生命周期回调

基础组件

当前基础组件的生命周期包含onAppearonDisAppearonAttachonDetach,通过属性的方式注册到后端的EventHub中保存。 当组件上树时触发onAttachonAppear

void FrameNode::OnAttachToMainTree(bool recursive)
{
    TriggerRsProfilerNodeMountCallbackIfExist();
    eventHub_->FireOnAttach();
    eventHub_->FireOnAppear();
    ...
}

eventHub_->FireOnAttach在挂树后立即执行

void EventHub::FireOnAttach()
{
    if (onAttach_) {
        auto onAttach = onAttach_;
        onAttach();
    }
}

eventHub_->FireOnAppearVsync消息后执行

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");
    }
}

组件下树触发onDetachonDisAppear

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生命周期

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言