HarmonyOS 6 API22新特性NDK支持多线程创建组件能力介绍

在HarmonyOS应用开发中,UI组件的创建与渲染性能直接影响用户体验。随着应用功能日益复杂,动态创建大量UI组件的场景愈发普遍,而传统单线程创建模式的性能瓶颈逐渐凸显。HarmonyOS 6 API version 22(以下简称API22)针对性地推出NDK多线程创建组件能力,彻底打破了UI线程的单一限制,为高性能UI开发提供了全新解决方案。本文将从特性价值、使用方式、适配规范、接口规格及实战示例等方面,全面解析这一核心新特性。

一、概述:突破UI线程限制的核心价值

1.1 传统模式的性能瓶颈

在API22之前,HarmonyOS的UI组件创建、属性设置等操作被严格限制在应用的UI线程中执行。这一限制给NDK接口对接带来了诸多不便:开发者必须将组件创建任务通过任务队列提交至UI线程,不仅增加了开发复杂度,更关键的是,当需要动态创建大量组件时,所有任务会堆积在单一UI线程中串行执行。这种模式会直接导致应用启动缓慢、动画丢帧、页面卡顿等问题,尤其在复杂业务场景下,用户体验大打折扣。

1.2 多线程NDK能力的核心提升

API22引入的NDK多线程支持能力,从根本上解决了上述问题,为开发者带来三大核心提升:

  • 简化调用流程:无需主动切换线程或通过任务队列提交任务,可在任意线程直接调用组件创建接口。这不仅减少了线程上下文切换的开销,还大幅简化了UI框架与应用间的交互逻辑,降低了开发成本。
  • 性能与体验显著优化:组件创建、属性设置等接口支持多线程并发调用,能充分利用设备多核CPU的算力,大幅降低页面创建阶段的总体耗时。同时,UI线程可专注于动画渲染与用户输入响应,确保界面流畅度和交互及时性。
  • 扩展灵活性更强:多线程调用能力不仅解决了当前的性能瓶颈,更为未来复杂、高负载UI页面的开发提供了扩展空间。开发者在架构设计时拥有更多自由度,为持续优化用户体验奠定基础。
    所以在页面跳转、列表滑动等高性能需求场景中,多线程NDK接口将成为提升UI创建效率的核心工具。

二、多线程NDK接口使用方式:简洁适配,降低成本

为降低开发者的适配成本,API22的多线程NDK接口在获取和使用方式上与现有NDK接口保持一致,核心只需完成“接口获取-任务调度”两步操作。

2.1 核心接口获取

通过OH_ArkUI_GetModuleInterface接口,传入ARKUI_MULTI_THREAD_NATIVE_NODE参数,即可获取多线程NDK接口集合。示例代码如下:

ArkUI_NativeNodeAPI_1 *multiThreadNodeAPI = nullptr;
// 获取多线程NDK接口集合
OH_ArkUI_GetModuleInterface(ARKUI_MULTI_THREAD_NATIVE_NODE, ArkUI_NativeNodeAPI_1, multiThreadNodeAPI);
if (!multiThreadNodeAPI) {
return; // 接口获取失败,需处理异常
}
// 调用createNode接口创建UI组件(支持非UI线程直接调用)
multiThreadNodeAPI->createNode(ARKUI_NODE_COLUMN);

说明:获取接口后,即可直接调用集合中的多线程支持接口(如组件创建、属性设置等),无需额外的线程切换逻辑。
这里需要注意的是需要升级IDE,使用API22的 SDK开发,否则会报错:
在这里插入图片描述

2.2 任务调度接口使用

根据线程创建方(系统线程池/自定义线程)及任务需求(异步/同步),需选择对应的任务调度接口,将组件创建放在子线程,将组件挂载等关键操作提交至UI线程执行。核心调度接口分为三类:

  1. OH_ArkUI_PostAsyncUITask:用于将组件创建、属性设置等任务调度到系统线程池执行,组件创建完成后,自动将挂载任务提交至UI线程。无需开发者手动管理线程,推荐优先使用。
  2. OH_ArkUI_PostUITask:用于开发者自定义非UI线程创建组件的场景,需手动将组件挂载到主树的任务提交至UI线程。
  3. OH_ArkUI_PostUITaskAndWait:用于多线程创建过程中需调用UI线程专属函数的场景。调用此接口的非UI线程会等待UI线程函数执行完成后再继续,需注意:UI线程负载过高时可能导致非UI线程长时间阻塞,影响性能收益,不建议频繁使用。

三、适配说明与线程安全:规避风险,高效应用

3.1 适用场景与线程数量建议

多线程NDK接口优先适用于页面跳转、列表滑动等高负载、性能敏感场景——此类场景中,UI线程需执行几ms到几十ms的组件创建任务,拆分后并发执行可显著降低UI线程负载。
线程数量建议:基于设备CPU核数等客观条件,自定义非UI线程的并行数量不超过4个,避免因线程过多导致调度开销增大,反而降低性能。
优化技巧:可在非UI线程预创建常用组件树,在性能敏感场景直接复用,进一步提升用户体验。

3.2 线程安全核心规则

多线程操作的线程安全性直接影响应用稳定性,需严格遵循以下规则:

  • 安全场景:多个线程同时操作不同组件时,线程安全;
  • 不安全场景:多个线程同时操作同一个组件或组件树时,非线程安全,可能导致不可预测的崩溃;
  • 组件状态限制:
    • Free(游离状态):组件未挂载到UI主树,可在任意线程通过多线程NDK接口操作;
    • Attached(已挂载状态):组件已挂载到UI主树,交由UI流水线管理,必须在UI线程操作,否则返回错误码ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD
  • 非多线程组件限制:通过非多线程NDK接口创建的组件(如ArkTS组件)由UI流水线管理,必须在UI线程操作;非必要场景不建议用多线程NDK接口操作此类组件,否则返回错误码。

3.3 特殊注意事项

若在多线程创建的组件树中挂载了不安全的ArkTS组件,需注意:

  1. 挂载ArkTS组件后,不可再在非UI线程操作该组件,否则可能因访问不安全组件导致应用崩溃;
  2. 需在UI线程移除所有挂载的ArkTS组件后,才能重新在非UI线程操作该组件;
  3. ArkUI框架会在组件从UI主树卸载前检查是否包含不安全组件,若存在则打印日志:CheckIsThreadSafeNodeTree failed. thread safe node tree contains unsafe node: ${nodeid}

四、错误与异常:关键错误码解析

多线程NDK接口调用的异常场景均会返回特定错误码,我们可以通过错误码快速定位问题。核心错误码ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD对应以下三种场景:

  • 在非UI线程调用多线程NDK接口集合中不支持多线程的接口;
  • 组件挂载到UI主树后,在非UI线程调用接口操作该组件;
  • 在非UI线程调用接口操作非多线程NDK接口创建的组件(如ArkTS组件)。
    建议:调用所有多线程NDK接口时,均需检查返回值,及时处理异常场景。

五、多线程NDK接口集合规格:清晰区分支持范围

多线程NDK接口集合包含两类接口:支持多线程调用的核心接口、仅支持UI线程调用的辅助接口。我们需要严格区分接口支持范围,避免违规调用。

5.1 支持多线程调用的接口

支持多线程调用的接口覆盖组件创建、属性操作、事件管理等核心能力,具体如下表:

接口名 描述 多线程规格
createNode 基于节点类型生成对应UI节点,返回节点对象指针 支持任意线程调用
disposeNode 销毁指定节点对象 在非UI线程调用函数操作已挂载到UI树上的节点时,接口调用无效。
setAttribute 设置节点属性 非UI线程操作已挂载节点,返回错误码
getAttribute 获取节点属性 非UI线程操作已挂载节点,返回空指针
resetAttribute 重置节点属性为默认值 非UI线程操作已挂载节点,返回错误码
setLengthMetricUnit 指定节点长度单位 非UI线程操作已挂载节点,返回错误码
registerNodeEvent 为节点注册事件 非UI线程操作已挂载节点,返回错误码
unregisterNodeEvent 为节点解注册事件 非UI线程操作已挂载节点,接口无效
registerNodeCustomEvent 为节点注册自定义事件 非UI线程操作已挂载节点,返回错误码
unregisterNodeCustomEvent 为节点解注册自定义事件 非UI线程操作已挂载节点,接口无效
addNodeEventReceiver 注册节点事件回调函数 非UI线程操作已挂载节点,返回错误码
removeNodeEventReceiver 删除节点事件回调函数 非UI线程操作已挂载节点,返回错误码
add/removeNodeCustomEventReceiver 注册/删除自定义事件回调函数 非UI线程操作已挂载节点,返回错误码
addChild/removeChild 添加/移除子节点 非UI线程操作已挂载节点,返回错误码
insertChildAfter/before/At 指定位置插入子节点 非UI线程操作已挂载节点,返回错误码
getParent 获取父节点 非UI线程操作已挂载节点,返回错误码
removeAllChildren 移除所有子节点 非UI线程操作已挂载节点,返回错误码
getTotalChildCount 获取子节点个数 非UI线程操作已挂载节点,返回0
getChildAt/getFirstChild/getLastChild 获取指定位置/首尾子节点 非UI线程操作已挂载节点,返回空指针
getPreviousSibling/getNextSibling 获取前后兄弟节点 非UI线程操作已挂载节点,返回空指针
setUserData 保存节点自定义数据 非UI线程操作已挂载节点,返回错误码
getUserData 获取节点自定义数据 非UI线程操作已挂载节点,返回空指针

5.2 仅支持UI线程调用的接口

仅支持UI线程调用的接口主要为全局事件管理和组件测算布局相关,非UI线程调用会导致接口无效或返回错误码,具体如下:

接口类别 接口名 描述
register/unregisterNodeEventReceiver 注册/解注册节点事件回调统一入口 接口不生效
register/unregisterNodeCustomEventReceiver 注册/解注册自定义事件回调统一入口 接口不生效
setMeasuredSize 设置组件测算后宽高 返回错误码
setLayoutPosition 设置组件布局位置 返回错误码
getMeasuredSize/getLayoutPosition 获取组件测算后宽高/布局位置 强制标记组件需重新测算/布局/绘制
measureNode/layoutNode 组件测算/布局 返回错误码
markDirty 强制标记组件需重新测算/布局/绘制 接口不生效

六、实战示例:多线程创建Button组件完整流程

本示例实现“点击按钮触发多线程创建Button组件”的场景:点击创建节点树按钮,在系统线程池和自定义非UI线程并行创建Button组件,创建完成后在UI线程挂载到主树;点击销毁节点树按钮,卸载并销毁组件。示例包含ETS页面、C++核心逻辑、工程配置等完整代码。

6.1 工程结构

工程整体代码结构如下:

entry/
├── src/main/
│ ├── ets/
│ │ └── pages/
│ │ | └── index.ets // 页面UI,包含按钮和组件挂载点
│ ├── cpp/
│ │ └── types/
│ │ └── libentry/
│ │ | └── Index.d.ts // NAPI接口声明
│ │ | └── oh-package.json5 // NAPI接口声明
│ │ ├── napi_init.cpp // NAPI接口注册
│ │ ├── NativeEntry.h // 入口声明
│ │ ├── NativeModule.h // 多线程接口封装
│ │ ├── ArkUIBaseNode.h // 基础节点封装
│ │ ├── ArkUINode.h // 节点封装
│ │ ├── CreateNode.h // 组件创建声明
│ │ ├── CreateNode.cpp // 多线程创建核心逻辑
│ | └── CMakeLists.txt // 工程配置
└── oh-package.json5 // 依赖配置

示例工程结构截图如下:
在这里插入图片描述

6.2 核心代码实现

6.2.1 页面UI(index.ets)

ArkTS模块中页面入口代码如下:

// index.ets  
import { NodeContent } from '@kit.ArkUI';  
import entry from 'libentry.so';  
  
@Component  
struct CAPIComponent {  
  private rootSlot = new NodeContent();  
  
  aboutToAppear(): void {  
    // 页面显示前多线程创建Native组件。  
    entry.createNodeTreeOnMultiThread(this.rootSlot, this.getUIContext());  
  }  
  
  aboutToDisappear(): void {  
    // 页面销毁前释放已创建的Native组件。  
    entry.disposeNodeTreeOnMultiThread(this.rootSlot);  
  }  
  
  build() {  
    Column() {  
      // Native组件挂载点。  
      ContentSlot(this.rootSlot)  
    }  
  }}  
  
@Entry  
@Component  
struct Index {  
  @State isShow: boolean = false;  
  @State message: string = "创建节点树";  
  
  build() {  
    Flex() {  
      Column() {  
        Text('CreateNodeTreeOnMultiThread')  
          .fontSize(18)  
          .fontWeight(FontWeight.Bold)  
        Button(this.message)  
          .onClick(() => {  
            this.isShow = !this.isShow;  
            if (this.isShow) {  
              this.message = "销毁节点树"  
            } else {  
              this.message = "创建节点树"  
            }  
          })  
        if (this.isShow) {  
          CAPIComponent()  
        }  
      }.width('100%')  
    }.width('100%')  
  }  
}

自定义组件CAPIComponent封装了Native层UI节点。

6.2.2 多线程接口封装(NativeModule.h)
#ifndef MYAPPLICATION_NATIVEMODULE_H  
#define MYAPPLICATION_NATIVEMODULE_H  
  
#include <arkui/native_node.h>  
#include <arkui/native_interface.h>  
#include <cassert>  
  
#include <arkui/native_interface.h>  
  
  
namespace NativeModule {  
  
class NativeModuleInstance {  
public:  
    static NativeModuleInstance *GetInstance() {  
        static NativeModuleInstance instance;  
        return &instance;  
    }  
  
    NativeModuleInstance() {  
        // 获取多线程NDK接口的函数指针结构体对象,用于后续操作。  
        OH_ArkUI_GetModuleInterface(ARKUI_MULTI_THREAD_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_);  
        assert(arkUINativeNodeApi_);  
    }  
    // 暴露给其他模块使用。  
    ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; }  
  
private:  
    ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr;  
};  
} // namespace NativeModule  
  
#endif // MYAPPLICATION_NATIVEMODULE_H

6.2.3 组件封装与多线程创建逻辑(CreateNode.cpp)
// CreateNode.cpp  
#include "CreateNode.h"  
  
#include <cstdint>  
#include <hilog/log.h>  
#include <map>  
#include <thread>  
#include <napi/native_api.h>  
#include <arkui/native_node_napi.h>  
  
namespace NativeModule {  
#define FRAMEWORK_NODE_TREE_NUMBER 4 // 在框架线程创建组件树的数量。  
#define USER_NODE_TREE_NUMBER 3 // 在开发者线程创建组件树的数量。  
struct AsyncData {  
    napi_env env;  
    std::shared_ptr<ArkUINode> parent = nullptr;  
    std::shared_ptr<ArkUINode> child = nullptr;  
    std::string label = "";  
};  
  
// 保存ArkTs侧NodeContent指针与Native侧节点树根节点的对应关系。  
std::map<ArkUI_NodeContentHandle, std::shared_ptr<ArkUIBaseNode>> g_nodeMap;  
ArkUI_ContextHandle g_contextHandle = nullptr;  
  
// 创建组件树。  
void CreateNodeTree(void *asyncUITaskData) {  
    auto asyncData = static_cast<AsyncData*>(asyncUITaskData);  
    if (!asyncData) {  
        return;  
    }  
    // 创建组件树根节点。  
    auto rowNode = std::make_shared<ArkUIRowNode>();  
    asyncData->child = rowNode;  
      
    // 创建button组件。  
    auto buttonNode1 = std::make_shared<ArkUIButtonNode>();  
    ArkUI_AttributeItem label_item = { .string = asyncData->label.c_str() };  
    // 设置button组件的label属性。  
    int32_t result = buttonNode1->SetLabel(label_item);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "Button SetLabel Failed %{public}d", result);  
    }  
    ArkUI_NumberValue value[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5}};  
    ArkUI_AttributeItem item = {value, 4};  
    // 设置button组件的margin属性。  
    result = buttonNode1->SetMargin(item);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "Button SetMargin Failed %{public}d", result);  
    }  
    // 设置button组件的width属性。  
    buttonNode1->SetWidth(150);  
     
   // 创建button组件。  
    auto buttonNode2 = std::make_shared<ArkUIButtonNode>();  
    ArkUI_AttributeItem label_item2 = { .string = asyncData->label.c_str() };  
    // 设置button组件的label属性。  
    result = buttonNode2->SetLabel(label_item2);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "Button SetLabel Failed %{public}d", result);  
    }  
    ArkUI_NumberValue value2[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5}};  
    ArkUI_AttributeItem item2 = {value2, 4};  
    // 设置button组件的margin属性。  
    result = buttonNode1->SetMargin(item2);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "Button SetMargin Failed %{public}d", result);  
    }  
    // 设置button组件的width属性。  
    buttonNode2->SetWidth(150);  
  
    // 把组件挂载到组件树上。  
    rowNode->AddChild(buttonNode1);  
    rowNode->AddChild(buttonNode2);  
}  
  
// 把组件树挂载到UI组件主树上。  
void MountNodeTree(void *asyncUITaskData) {  
    auto asyncData = static_cast<AsyncData*>(asyncUITaskData);  
    if (!asyncData) {  
        return;  
    }  
    auto parent = asyncData->parent;  
    auto child = asyncData->child;  
    // 把组件树挂载到UI组件主树上。  
    parent->AddChild(child);  
    delete asyncData;  
}  
  
void CreateNodeOnFrameworkThread(ArkUI_ContextHandle contextHandle, std::shared_ptr<ArkUIColumnNode> parent) {  
    for (int i = 0; i < FRAMEWORK_NODE_TREE_NUMBER; i++) {  
        // UI线程创建子树根节点,保证scroll的子节点顺序。  
        auto columnItem = std::make_shared<ArkUIColumnNode>();  
        parent->AddChild(columnItem);  
        AsyncData* asyncData = new AsyncData();  
        asyncData->parent = columnItem;  
        asyncData->label = "OnFwkThread";  
        // 使用框架提供的非UI线程创建组件树,创建完成后回到UI线程挂载到主树上。  
        int32_t result = OH_ArkUI_PostAsyncUITask(contextHandle, asyncData, CreateNodeTree, MountNodeTree);  
        if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
            OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostAsyncUITask Failed %{public}d", result);  
            delete asyncData;  
        }  
    }  
}  
  
void CreateNodeOnUserThread(ArkUI_ContextHandle contextHandle, std::shared_ptr<ArkUIColumnNode> parent) {  
    auto columnItem = std::make_shared<ArkUIColumnNode>();  
    parent->AddChild(columnItem);  
    // 在开发者创建的非UI线程上创建组件树。  
    std::thread userThread([columnItem, contextHandle]() {  
        for (int i = 0; i < USER_NODE_TREE_NUMBER; i++) {  
            AsyncData* asyncData = new AsyncData();  
            asyncData->parent = columnItem;  
            asyncData->label = "用户线程1";  
            CreateNodeTree(asyncData);  
            // 组件树创建完成后回到UI线程挂载到主树上。  
            int32_t result = OH_ArkUI_PostUITask(contextHandle, asyncData, MountNodeTree);  
            if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
                OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostUITask Failed %{public}d", result);  
                delete asyncData;  
            }  
        }  
    });  
    userThread.detach();  
}  
  
void CreateNodeOnUserThreadAndWait(ArkUI_ContextHandle contextHandle, std::shared_ptr<ArkUIColumnNode> parent) {  
    auto columnItem = std::make_shared<ArkUIColumnNode>();  
    parent->AddChild(columnItem);  
    // 在开发者创建的非UI线程上创建组件树。  
    std::thread userThread([columnItem, contextHandle]() {  
        for (int i = 0; i < USER_NODE_TREE_NUMBER; i++) {  
            AsyncData* asyncData = new AsyncData();  
            asyncData->parent = columnItem;  
            asyncData->label = "用户线程2";  
            CreateNodeTree(asyncData);  
            // 组件树创建完成后回到UI线程挂载到主树上,等待挂载完成后继续创建剩余组件。  
            int32_t result = OH_ArkUI_PostUITaskAndWait(contextHandle, asyncData, MountNodeTree);  
            if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
                OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostUITask Failed %{public}d", result);  
                delete asyncData;  
            }  
        }  
    });  
    userThread.detach();  
}  
  
napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info) {  
    size_t argc = 2;  
    napi_value args[2] = { nullptr, nullptr };  
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);  
  
    // 获取ArkTs侧组件挂载点。  
    ArkUI_NodeContentHandle contentHandle;  
    int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result);  
        return nullptr;  
    }  
      
    // 获取上下文对象指针。  
    if (!g_contextHandle) {  
        result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &g_contextHandle);  
        if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
            OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result);  
            delete g_contextHandle;  
            g_contextHandle = nullptr;  
            return nullptr;  
        }  
    }  
      
    // 创建Native侧组件树根节点。  
    auto scrollNode = std::make_shared<ArkUIScrollNode>();  
    // 将Native侧组件树根节点挂载到UI主树上。  
    result = OH_ArkUI_NodeContent_AddNode(contentHandle, scrollNode->GetHandle());  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_AddNode Failed %{public}d", result);  
        return nullptr;  
    }  
    // 保存Native侧组件树。  
    g_nodeMap[contentHandle] = scrollNode;  
      
    auto columnNode = std::make_shared<ArkUIColumnNode>();  
    scrollNode->AddChild(columnNode);  
    // 在框架提供的线程池中创建组件。  
    CreateNodeOnFrameworkThread(g_contextHandle,columnNode);  
    // 在开发者创建的非UI线程中创建组件。  
    CreateNodeOnUserThread(g_contextHandle,columnNode);  
    CreateNodeOnUserThreadAndWait(g_contextHandle,columnNode);  
    return nullptr;  
}  
  
napi_value DisposeNodeTreeOnMultiThread(napi_env env, napi_callback_info info)  
{  
    size_t argc = 1;  
    napi_value args[1] = { nullptr };  
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);  
  
    // 获取ArkTs侧组件挂载点。  
    ArkUI_NodeContentHandle contentHandle;  
    int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result);  
        return nullptr;  
    }  
      
    auto it = g_nodeMap.find(contentHandle);  
    if (it == g_nodeMap.end()) {  
        return nullptr;  
    }  
    auto rootNode = it->second;  
    // 将Native侧组件树根节点从UI主树上卸载。  
    result = OH_ArkUI_NodeContent_RemoveNode(contentHandle, rootNode->GetHandle());  
    if (result != ARKUI_ERROR_CODE_NO_ERROR) {  
        OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_RemoveNode Failed %{public}d", result);  
        return nullptr;  
    }  
    // 释放Native侧组件树。  
    g_nodeMap.erase(contentHandle);  
    return nullptr;  
}  
} // namespace NativeModule

Button组件封装:

// 封装Button组件。  
class ArkUIButtonNode: public ArkUINode {  
public:  
    ArkUIButtonNode() :  
        ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_BUTTON)) {  
            ArkUI_NumberValue value_color[] = {{.u32 = 0xffFD8A6B}};  
            ArkUI_AttributeItem item_color = {value_color, 1};  
            nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item_color);  
            ArkUI_NumberValue value_color1[] = {{.u32 = 0xFFFFFFFF}};  
            ArkUI_AttributeItem item_color1 = {value_color1, 1};  
            nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item_color1);  
        }  
    int32_t SetLabel(ArkUI_AttributeItem& label_item) {  
        return nativeModule_->setAttribute(handle_, NODE_BUTTON_LABEL, &label_item);  
    }  
    int32_t SetMargin(ArkUI_AttributeItem& item) {  
        return nativeModule_->setAttribute(handle_, NODE_MARGIN, &item);  
    }  
};
6.2.4 工程配置(CMakeLists.txt)
# CMakeLists.txt  
# the minimum version of CMake.  
cmake_minimum_required(VERSION 3.5.0)  
project(ndk_build_on_multi_thread)  
  
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})  
  
if(DEFINED PACKAGE_FIND_FILE)  
    include(${PACKAGE_FIND_FILE})  
endif()  
  
include_directories(${NATIVERENDER_ROOT_PATH}  
                    ${NATIVERENDER_ROOT_PATH}/include)  
  
add_library(entry SHARED napi_init.cpp NativeEntry.cpp NativeModule.h ArkUIBaseNode.h ArkUINode.h CreateNode.h CreateNode.cpp)  
target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so libhilog_ndk.z.so)

6.3 示例运行说明

  1. 编译运行工程,点击页面中的创建节点树按钮,触发多线程创建Button组件;
  2. 系统线程池(4个)和自定义线程(2个,分别异步/同步挂载)并行创建Button组件,组件创建完成后自动挂载到UI主树,页面显示带有“系统框架线程”、“用户线程1”、“用户线程2”标签的Button;
  3. 点击销毁节点树按钮,组件从UI主树卸载并销毁,页面清空。
    运行效果如下:
    在这里插入图片描述

在ArkUI Inspector中可以看到页面整个结构,ArkTS层CAPIComponent包含了Native层创建的组件,根布局是Column,里面是创建的Button组件:
在这里插入图片描述

七、总结

HarmonyOS 6 API22推出的NDK多线程创建组件能力,通过打破UI线程的单一限制,为复杂UI场景提供了高性能解决方案。其核心优势在于简化开发流程、充分利用多核算力、提升扩展灵活性,同时通过清晰的接口规格和线程安全规则,降低了开发者的适配风险。
在实际开发中,建议优先在页面跳转、列表滑动等性能敏感场景应用该特性,合理控制并行线程数量,严格遵循组件状态和接口调用规范。结合本文提供的实战示例,开发者可快速上手多线程NDK接口的使用,为应用打造更流畅的UI体验。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐