ArkUI页面首次创建流程介绍(3.0版本)

页面首次创建流程介绍

流程示意

在这里插入图片描述

  1. 框架初始化:主要初始化框架的上下文环境,包括containter容器、pipeline渲染管线、rootNode根节点等;
  2. 页面加载:在框架初始化完成后,会执行页面文件,页面文件执行时会生成后端的页面节点树,并挂载到渲染管线的根节点上;
  3. 布局渲染:页面节点挂载完成后,会触发相应的布局和渲染任务,进行布局渲染。
    下面分别从这三个阶段具体展开进行分析说明。

框架初始化

在这里插入图片描述
在这里插入图片描述

Ability初始化

Ability是系统调度应用的最小单元,通过JS引擎隔离开发者代码。其中,每个Ability都有自己的UI线程,实现并行渲染。

  • 初始化当前进程
std::call_once(onceFlag, [abilityContext, cacheDir]() {
      LOGI("Initialize for current process.");
      SetHwIcuDirectory();
      Container::UpdateCurrent(INSTANCE_ID_PLATFORM);
      CapabilityRegistry::Register();
      AceApplicationInfo::GetInstance().SetPackageName(abilityContext->GetBundleName());
      AceApplicationInfo::GetInstance().SetDataFileDirPath(abilityContext->GetFilesDir());
      AceApplicationInfo::GetInstance().SetApiTargetVersion(abilityContext->GetApplicationInfo()->apiTargetVersion);
      AceApplicationInfo::GetInstance().SetAppVersionName(abilityContext->GetApplicationInfo()->versionName);
      AceApplicationInfo::GetInstance().SetAppVersionCode(abilityContext->GetApplicationInfo()->versionCode);
      AceApplicationInfo::GetInstance().SetUid(IPCSkeleton::GetCallingUid());
      AceApplicationInfo::GetInstance().SetPid(IPCSkeleton::GetCallingPid());
      ImageCache::SetImageCacheFilePath(cacheDir);
      ImageCache::SetCacheFileInfo();
      AceEngine::InitJsDumpHeadSignal();
  });
  • 添加监听器:添加各种Listener
   window->RegisterWindowChangeListener(aceWindowListener);
   // register drag event callback
   window->RegisterDragListener(aceWindowListener);
   // register Occupied Area callback
   window->RegisterOccupiedAreaChangeListener(aceWindowListener);
   // register ace ability handler callback
   window->SetAceAbilityHandler(aceWindowListener);
   // register input consumer callback
   std::shared_ptr<AceWindowListener> aceInputConsumer = std::make_shared<AceWindowListener>(self);
   window->SetInputEventConsumer(aceInputConsumer);
  • 获取默认参数:
auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
  • 获取资源管理器信息:
auto resourceManager = GetResourceManager();
  • 获取各种配置
 	auto packagePathStr = GetBundleCodePath();
    auto moduleInfo = GetHapModuleInfo();
  • 将各种Message赋给Ability
Containter和View初始化
Container初始化

ace_ability.cpp

Platform::AceContainer::CreateContainer(abilityId_, frontendType, srcPath, shared_from_this(),
        std::make_unique<AcePlatformEventCallback>([this]() { TerminateAbility(); },
            [this](const std::string& address) {
                AAFwk::Want want;
                want.AddEntity(Want::ENTITY_BROWSER);
                want.SetUri(address);
                want.SetAction(ACTION_VIEWDATA);
                this->StartAbility(want);
            }),
        false, useNewPipe);
  • 将Container加入到Ace引擎当中
AceEngine::Get().AddContainer(instanceId, aceContainer);
View初始化

ace_ability.cpp

Platform::AceContainer::SetView(aceView, density_, 0, 0, window, callback);
pipeline初始化

ace_ability.cpp
在Ability初始化后便开始进行

auto apiCompatibleVersion = abilityContext->GetApplicationInfo()->apiCompatibleVersion;
auto apiReleaseType = abilityContext->GetApplicationInfo()->apiReleaseType;
auto apiTargetVersion = abilityContext->GetApplicationInfo()->apiTargetVersion;
auto useNewPipe = AceNewPipeJudgement::QueryAceNewPipeEnabledFA(
AceApplicationInfo::GetInstance().GetPackageName(), apiCompatibleVersion, apiTargetVersion, apiReleaseType);
LOGI("AceAbility: apiCompatibleVersion: %{public}d, apiTargetVersion: %{public}d, and apiReleaseType: %{public}s, "
        "useNewPipe: %{public}d",
       apiCompatibleVersion, apiTargetVersion, apiReleaseType.c_str(), useNewPipe);

之后在ace_container.cpp中将其置为true,开始使用

	//ace_container.cpp
   if (useNewPipeline) {
       SetUseNewPipeline();
   }
   //container.h
   void SetUseNewPipeline()
   {
       useNewPipeline_ = true;
   }
rootNode根节点初始化

ace_container.cpp

RefPtr<NG::FrameNode> rootNode = context->GetRootElement();
rootNode->UpdateConfigurationUpdate(configurationChange);

页面加载

在这里插入图片描述

原始文件

@Entry
@Component
struct Index {
 @State message: string = 'Hello World'

 build() {
   Stack() {
   }.width('80%').height('80%')
   .backgroundColor('#fff111')
 }
}
执行页面文件

使用IDE编译后待执行文件(entry/build/default/intermediates/assets/default/js/MainAbility/pages/index.js)

var _ff3b25f72d479da6a3314472b8401bae;
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!*******************************************************************************************************************!*\
 !*** ../../../../../../DevEcoStudioProjects/MyApplication17/entry/src/main/ets/MainAbility/pages/index.ets?entry ***!
 \*******************************************************************************************************************/
class Index extends View {
   constructor(compilerAssignedUniqueChildId, parent, params) {
       super(compilerAssignedUniqueChildId, parent);
       this.__message = new ObservedPropertySimple('Hello World', this, "message");
       this.updateWithValueParams(params);
   }
   updateWithValueParams(params) {
       if (params.message !== undefined) {
           this.message = params.message;
       }
   }
   aboutToBeDeleted() {
       this.__message.aboutToBeDeleted();
       SubscriberManager.Get().delete(this.id());
   }
   get message() {
       return this.__message.get();
   }
   set message(newValue) {
       this.__message.set(newValue);
   }
   render() {
       Stack.create();
       Stack.width('80%');
       Stack.height('80%');
       Stack.backgroundColor('#fff111');
       Stack.pop();
   }
}
loadDocument(new Index("1", undefined, {}));

_ff3b25f72d479da6a3314472b8401bae = __webpack_exports__;
/******/ })()
;
//# sourceMappingURL=index.js.map
生成页面节点树

执行JS页面文件时,会执行上面的全局方法loadDocument,在loadDocument函数中会创建相应的UI对象进行渲染加载。

  • loadDocument全局函数,在C++侧通过JS引擎注入相关定义(foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsi/jsi_view_register.cpp)
void JsRegisterViews(BindingTarget globalObj)
{
   auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
   if (!runtime) {
       LOGE("JsRegisterViews can't find runtime");
   }
   auto vm = runtime->GetEcmaVm();
   globalObj->Set(vm, panda::StringRef::NewFromUtf8(vm, "loadDocument"),
       panda::FunctionRef::New(const_cast<panda::EcmaVM*>(vm), JsLoadDocument));
   ...
}
panda::Local<panda::JSValueRef> JsLoadDocument(panda::JsiRuntimeCallInfo *runtimeCallInfo)
{
   LOGI("Load Document start");
   ...
   JSView* view = static_cast<JSView*>(obj->GetNativePointerField(0));
   ...
   if (Container::IsCurrentUseNewPipeline()) {
       auto pageRootNode = view->CreateNode();
       page->SetRootNode(pageRootNode);
   }
   ...
}
页面节点树挂载

在执行JsLoadDocument方法时,入参为new Index(“1”, undefined, {})对象,该对象由于在C++侧注入了基类的定义,会走ConstructorCallback回调,生成JSView的对象并保存Render方法,JSView* view = static_cast<JSView*>(obj->GetNativePointerField(0))调用在通过JS引擎的能力从对象中获取我们生成的JSView对象,并调用JSView的对象创建page节点。

void JSView::JSBind(BindingTarget object)
{
   JSClass<JSView>::Declare("NativeView");
   ...
   JSClass<JSView>::Inherit<JSViewAbstract>();
   JSClass<JSView>::Bind(object, ConstructorCallback, DestructorCallback);
}
void JSView::ConstructorCallback(const JSCallbackInfo& info)
{
   JSRef<JSObject> thisObj = info.This();
   JSRef<JSVal> renderFunc = thisObj->GetProperty("render");
   if (!renderFunc->IsFunction()) {
       LOGE("View derived classes must provide render(){...} function");
       JSException::Throw("%s", "View derived classes must provide render(){...} function");
       return;
   }

   int argc = info.Length();
   if (argc > 1 && (info[0]->IsNumber() || info[0]->IsString())) {
       std::string viewId = info[0]->ToString();
       auto instance = AceType::MakeRefPtr<JSView>(viewId, info.This(), JSRef<JSFunc>::Cast(renderFunc));
   	...
       LOGD("JSView ConstructorCallback: %{public}s", instance->id_.c_str());
   } else {
       LOGE("JSView creation with invalid arguments.");
       JSException::Throw("%s", "JSView creation with invalid arguments.");
   }
}

内部Render方法(RefPtrNG::FrameNode JSView::CreateNode())会在页面布局加载时进行对应,而这些JS的静态方法,包括: Stack.create();Stack.width(‘80%’);Stack.height(‘80%’);Stack.backgroundColor(‘#fff111’);Stack.pop(),在C++侧通过JS引擎注入定义,在执行JS代码时会分别走到对应的C++侧绑定方法来生成节点并设置属性。

void JSStack::JSBind(BindingTarget globalObj)
{
  JSClass<JSStack>::Declare("Stack");
  MethodOptions opt = MethodOptions::NONE;
  JSClass<JSStack>::StaticMethod("create", &JSStack::Create, opt);
  ...
  JSClass<JSStack>::StaticMethod("width", SetWidth);
  JSClass<JSStack>::StaticMethod("height", SetHeight);
  ...
  JSClass<JSStack>::Bind<>(globalObj);
}
  • 执行JS代码时会走到对应C++侧绑定方法来创建相应的CustomNode的页面节点;
  • 执行完JS代码后,会调用StageManager对象将页面创建的节点挂载到对应的根节点上;
  • 根节点挂载页面节点后,会标记根节点为脏节点保存在UiTaskScheduler对象中;
  • UiTaskScheduler对象收到FlushLayout指令后开始创建布局和渲染任务。

布局渲染

  • Root节点标记为脏节点后,UiTaskScheduler会通过FlushLayout的方法调用Root节点的CreateLayoutTask任务
  • Root节点的LayoutTask任务会遍历子节点创建相应的LayoutWrapper布局包装任务;
  • LayoutWrapper布局包装任务会执行相关测算和布局任务;
    在测算任务中,Index的CustomNode节点创建的LayoutWrapper布局包装器中携带了RenderFunction方法(对应页面Index对象中的render()函数),该方法执行后会生成Stack节点;
  • 生成的Stack节点通过Index的LayoutWrapper包装器可以找到对应的Index的CustomNode节点,并将Stack节点挂载到Index的节点下;
  • CustomNode的LayoutWrapper创建完Stack节点后,会调用Stack节点的CreateLayoutWrapper方法创建对应的LayoutWrapper用于测算Stack节点的大小;
  • 布局任务完成后,LayoutWrapper树会根据内部引用的节点对象指针找到各自的Node节点并将计算完成后的大小位置信息赋值到Node节点;
  • Node节点检测到大小位置变更后,会创建相应的RenderWrapper绘制任务进行内容刷新绘制。
布局

在这里插入图片描述

渲染

在这里插入图片描述

展示

在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值