diff --git a/zh-cn/application-dev/reference/apis-arkui/_ark_u_i___native_module.md b/zh-cn/application-dev/reference/apis-arkui/_ark_u_i___native_module.md index 0bea4f37e08f7be48499c368becda24f60465289..effc43135b2489679368327806f258da0cb654b5 100644 --- a/zh-cn/application-dev/reference/apis-arkui/_ark_u_i___native_module.md +++ b/zh-cn/application-dev/reference/apis-arkui/_ark_u_i___native_module.md @@ -279,7 +279,7 @@ | [ArkUI_ListItemSwipeEdgeEffect](#arkui_listitemswipeedgeeffect) { ARKUI_LIST_ITEM_SWIPE_EDGE_EFFECT_SPRING = 0, ARKUI_LIST_ITEM_SWIPE_EDGE_EFFECT_NONE } | 定义 Listitem 组件SwipeAction方法的滚动模式。 | | [ArkUI_AnimationStatus](#arkui_animationstatus) { ARKUI_ANIMATION_STATUS_INITIAL, ARKUI_ANIMATION_STATUS_RUNNING, ARKUI_ANIMATION_STATUS_PAUSED, ARKUI_ANIMATION_STATUS_STOPPED } | 定义帧动画的播放状态。 | | [ArkUI_AnimationFillMode](#arkui_animationfillmode) { ARKUI_ANIMATION_FILL_MODE_NONE, ARKUI_ANIMATION_FILL_MODE_FORWARDS, ARKUI_ANIMATION_FILL_MODE_BACKWARDS, ARKUI_ANIMATION_FILL_MODE_BOTH } | 定义帧动画组件在动画开始前和结束后的状态。 | -| [ArkUI_ErrorCode](#arkui_errorcode) {
ARKUI_ERROR_CODE_NO_ERROR = 0, ARKUI_ERROR_CODE_PARAM_INVALID = 401, ARKUI_ERROR_CODE_CAPI_INIT_ERROR = 500, ARKUI_ERROR_CODE_INTERNAL_ERROR = 100001,
ARKUI_ERROR_CODE_XCOMPONENT_STATE_INVALID = 103501, ARKUI_ERROR_CODE_ATTRIBUTE_OR_EVENT_NOT_SUPPORTED = 106102, ARKUI_ERROR_CODE_ARKTS_NODE_NOT_SUPPORTED = 106103, ARKUI_ERROR_CODE_ADAPTER_NOT_BOUND = 106104,
ARKUI_ERROR_CODE_ADAPTER_EXIST = 106105, ARKUI_ERROR_CODE_CHILD_NODE_EXIST = 106106, ARKUI_ERROR_CODE_NODE_EVENT_PARAM_INDEX_OUT_OF_RANGE = 106107, ARKUI_ERROR_CODE_NODE_EVENT_PARAM_INVALID = 106108,
ARKUI_ERROR_CODE_NODE_EVENT_NO_RETURN = 106109, ARKUI_ERROR_CODE_NODE_INDEX_INVALID = 106200, ARKUI_ERROR_CODE_GET_INFO_FAILED = 106201, ARKUI_ERROR_CODE_BUFFER_SIZE_ERROR = 106202,
ARKUI_ERROR_CODE_NODE_NOT_ON_MAIN_TREE = 106203, ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE = 150001, ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE_ANCESTOR = 150002, ARKUI_ERROR_CODE_FOCUS_NON_EXISTENT = 150003,
ARKUI_ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT = 160002, ARKUI_ERROR_CODE_NON_SCROLLABLE_CONTAINER = 180001, ARKUI_ERROR_CODE_BUFFER_SIZE_NOT_ENOUGH = 180002, ARKUI_ERROR_CODE_NOT_CLONED_POINTER_EVENT = 180003,
ARKUI_ERROR_CODE_POST_CLONED_COMPONENT_STATUS_ABNORMAL = 180004, ARKUI_ERROR_CODE_POST_CLONED_NO_COMPONENT_HIT_TO_RESPOND_TO_THE_EVENT = 180005, ARKUI_ERROR_INPUT_EVENT_TYPE_NOT_SUPPORTED = 180006,
ARKUI_ERROR_CODE_INVALID_STYLED_STRING = 180101, ARKUI_ERROR_CODE_UI_CONTEXT_INVALID = 190001,
ARKUI_ERROR_CODE_CALLBACK_INVALID = 190002, ARKUI_ERROR_CODE_RECOGNIZER_TYPE_NOT_SUPPORTED = 180102, ARKUI_ERROR_CODE_DRAG_DROP_OPERATION_NOT_ALLOWED = 190004
} | 定义错误码枚举值。 | +| [ArkUI_ErrorCode](#arkui_errorcode) {
ARKUI_ERROR_CODE_NO_ERROR = 0, ARKUI_ERROR_CODE_PARAM_INVALID = 401, ARKUI_ERROR_CODE_CAPI_INIT_ERROR = 500, ARKUI_ERROR_CODE_INTERNAL_ERROR = 100001,
ARKUI_ERROR_CODE_XCOMPONENT_STATE_INVALID = 103501, ARKUI_ERROR_CODE_ATTRIBUTE_OR_EVENT_NOT_SUPPORTED = 106102, ARKUI_ERROR_CODE_ARKTS_NODE_NOT_SUPPORTED = 106103, ARKUI_ERROR_CODE_ADAPTER_NOT_BOUND = 106104,
ARKUI_ERROR_CODE_ADAPTER_EXIST = 106105, ARKUI_ERROR_CODE_CHILD_NODE_EXIST = 106106, ARKUI_ERROR_CODE_NODE_EVENT_PARAM_INDEX_OUT_OF_RANGE = 106107, ARKUI_ERROR_CODE_NODE_EVENT_PARAM_INVALID = 106108,
ARKUI_ERROR_CODE_NODE_EVENT_NO_RETURN = 106109, ARKUI_ERROR_CODE_NODE_INDEX_INVALID = 106200, ARKUI_ERROR_CODE_GET_INFO_FAILED = 106201, ARKUI_ERROR_CODE_BUFFER_SIZE_ERROR = 106202,
ARKUI_ERROR_CODE_NODE_NOT_ON_MAIN_TREE = 106203, ARKUI_ERROR_CODE_ON_INVALID_THREAD = 106204, ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE = 150001, ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE_ANCESTOR = 150002, ARKUI_ERROR_CODE_FOCUS_NON_EXISTENT = 150003,
ARKUI_ERROR_CODE_COMPONENT_SNAPSHOT_TIMEOUT = 160002, ARKUI_ERROR_CODE_NON_SCROLLABLE_CONTAINER = 180001, ARKUI_ERROR_CODE_BUFFER_SIZE_NOT_ENOUGH = 180002, ARKUI_ERROR_CODE_NOT_CLONED_POINTER_EVENT = 180003,
ARKUI_ERROR_CODE_POST_CLONED_COMPONENT_STATUS_ABNORMAL = 180004, ARKUI_ERROR_CODE_POST_CLONED_NO_COMPONENT_HIT_TO_RESPOND_TO_THE_EVENT = 180005, ARKUI_ERROR_INPUT_EVENT_TYPE_NOT_SUPPORTED = 180006,
ARKUI_ERROR_CODE_INVALID_STYLED_STRING = 180101, ARKUI_ERROR_CODE_UI_CONTEXT_INVALID = 190001,
ARKUI_ERROR_CODE_CALLBACK_INVALID = 190002, ARKUI_ERROR_CODE_RECOGNIZER_TYPE_NOT_SUPPORTED = 180102, ARKUI_ERROR_CODE_DRAG_DROP_OPERATION_NOT_ALLOWED = 190004
} | 定义错误码枚举值。 | | [ArkUI_ScrollSource](#arkui_scrollsource) {
ARKUI_SCROLL_SOURCE_DRAG = 0, ARKUI_SCROLL_SOURCE_FLING, ARKUI_SCROLL_SOURCE_EDGE_EFFECT, ARKUI_SCROLL_SOURCE_OTHER_USER_INPUT,
ARKUI_SCROLL_SOURCE_SCROLL_BAR, ARKUI_SCROLL_SOURCE_SCROLL_BAR_FLING, ARKUI_SCROLL_SOURCE_SCROLLER, ARKUI_SCROLL_SOURCE_ANIMATION
} | 定义滚动来源枚举值。 | | [ArkUI_SafeAreaType](#arkui_safeareatype) { ARKUI_SAFE_AREA_TYPE_SYSTEM = 1, ARKUI_SAFE_AREA_TYPE_CUTOUT = 1 << 1, ARKUI_SAFE_AREA_TYPE_KEYBOARD = 1 << 2 } | 定义扩展安全区域的枚举值。 | | [ArkUI_ListItemGroupArea](#arkui_listitemgrouparea) { ARKUI_LIST_ITEM_GROUP_AREA_OUTSIDE = 0, ARKUI_LIST_ITEM_SWIPE_AREA_NONE = 1, ARKUI_LIST_ITEM_SWIPE_AREA_ITEM = 2, ARKUI_LIST_ITEM_SWIPE_AREA_HEADER = 3, ARKUI_LIST_ITEM_SWIPE_AREA_FOOTER = 4
} | 定义组件区域的枚举值。 | @@ -2672,6 +2672,7 @@ enum ArkUI_ErrorCode | ARKUI_ERROR_CODE_GET_INFO_FAILED = 106201 | 查询路由导航信息失败。
错误码的详细介绍请参见[导航错误码](../apis-arkui/errorcode-router.md#106201-查询路由导航信息失败)。 | | ARKUI_ERROR_CODE_BUFFER_SIZE_ERROR = 106202 | 传入的buffer size异常。
错误码的详细介绍请参见[导航错误码](../apis-arkui/errorcode-router.md#106202-传入的buffer-size异常)。 | | ARKUI_ERROR_CODE_NODE_NOT_ON_MAIN_TREE = 106203 | 传入的节点未挂载到组件树上。
错误码的详细介绍请参见[自定义节点错误码](../apis-arkui/errorcode-node.md)。
起始版本:15 | +| ARKUI_ERROR_CODE_NODE_ON_INVALID_THREAD = 106204 | 此节点未在合法的线程上操作。
起始版本:20 | | ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE = 150001 | 当前节点无法获得焦点。
错误码的详细介绍请参见[焦点错误码](../apis-arkui/errorcode-focus.md#150001-节点无法获得焦点)。
起始版本:15 | | ARKUI_ERROR_CODE_FOCUS_NON_FOCUSABLE_ANCESTOR = 150002 | 当前节点对应的祖先节点中存在无法获焦节点。
错误码的详细介绍请参见[焦点错误码](../apis-arkui/errorcode-focus.md#150002-祖先节点无法获得焦点)。
起始版本:15 | | ARKUI_ERROR_CODE_FOCUS_NON_EXISTENT = 150003 | 当前节点不存在。
错误码的详细介绍请参见[焦点错误码](../apis-arkui/errorcode-focus.md#150003-节点不存在)。
起始版本:15 | @@ -3508,6 +3509,7 @@ enum ArkUI_NativeAPIVariantKind | ARKUI_NATIVE_DIALOG | 弹窗相关接口类型,详见<arkui/native_dialog.h>中的结构体类型定义。 | | ARKUI_NATIVE_GESTURE | 手势相关接口类型,详见<arkui/native_gesture.h>中的结构体类型定义。 | | ARKUI_NATIVE_ANIMATE | 动画相关接口类型。详见<arkui/native_animate.h>中的结构体类型定义。 | +| ARKUI_MULTI_THREAD_NATIVE_NODE | 支持非UI线程组件操作相关接口类型。详见<arkui/native_node.h>中的结构体类型定义。 | ### ArkUI_NavDestinationState @@ -19528,3 +19530,77 @@ void OH_ArkUI_EmbeddedComponentOption_SetOnTerminated(ArkUI_EmbeddedComponentOpt | option | EmbeddedComponent组件选项的对象的指针。| | code | 被拉起EmbeddedUIExtensionAbility退出时返回的结果码。若Ability通过调用terminateSelfWithResult退出,结果码为Ability设置的值。若Ability通过调用terminateSelf退出,结果码为默认值"0"。| | want | 被拉起EmbeddedUIExtensionAbility退出时返回的数据。| + +### OH_ArkUI_PostAsyncUITask() + +``` +int32_t OH_ArkUI_PostAsyncUITask(ArkUI_ContextHandle context, void* asyncUITaskData, + void (*asyncUITask)(void* asyncUITaskData), void (*onFinish)(void* asyncUITaskData)); +``` +**描述:** + +将UI任务抛到框架提供的非UI线程中执行。 + +**起始版本:** 20 + +**参数:** + +| 名称 | 描述 | +| -------- | -------- | +| uiContext | UI实例对象指针。 | +| asyncUITaskData | 开发者自定义数据指针,作为asyncUITask和onFinish的入参。 | +| asyncUITask| 在非UI线程执行的函数。| +| onFinish | asyncUITask执行完成后,在UI线程执行的函数。 | + +**返回:** + +[ARKUI_ERROR_CODE_NO_ERROR](_ark_u_i___native_module.md#arkui_errorcode) 成功。 +[ARKUI_ERROR_CODE_PARAM_INVALID](_ark_u_i___native_module.md#arkui_errorcode) 函数参数异常。 + +### OH_ArkUI_PostUITask() + +``` +int32_t OH_ArkUI_PostUITask(ArkUI_ContextHandle context, void* taskData, void (*task)(void* taskData)) +``` +**描述:** + +将UI任务抛到UI线程中执行。 + +**起始版本:** 20 + +**参数:** + +| 名称 | 描述 | +| -------- | -------- | +| uiContext | UI实例对象指针。 | +| taskData | 开发者自定义数据指针,作为task的入参。 | +| task | 在UI线程执行的函数。 | + +**返回:** + +[ARKUI_ERROR_CODE_NO_ERROR](_ark_u_i___native_module.md#arkui_errorcode) 成功。 +[ARKUI_ERROR_CODE_PARAM_INVALID](_ark_u_i___native_module.md#arkui_errorcode) 函数参数异常。 + +### OH_ArkUI_PostUITaskAndWait() + +``` +int32_t OH_ArkUI_PostUITaskAndWait(ArkUI_ContextHandle context, void* taskData, void (*task)(void* taskData)) +``` +**描述:** + +将UI任务抛到UI线程中执行并阻塞等待。 + +**起始版本:** 20 + +**参数:** + +| 名称 | 描述 | +| -------- | -------- | +| uiContext | UI实例对象指针。 | +| taskData | 开发者自定义数据指针,作为task的入参。 | +| task | 在UI线程执行的函数。 | + +**返回:** + +[ARKUI_ERROR_CODE_NO_ERROR](_ark_u_i___native_module.md#arkui_errorcode) 成功。 +[ARKUI_ERROR_CODE_PARAM_INVALID](_ark_u_i___native_module.md#arkui_errorcode) 函数参数异常。 diff --git a/zh-cn/application-dev/reference/apis-arkui/native__interface_8h.md b/zh-cn/application-dev/reference/apis-arkui/native__interface_8h.md index 888e6e2b91c70d9936150719dd6f519ec8a22f20..b63e20d6b6e78abc926f1940d1506078a1c1f9ed 100644 --- a/zh-cn/application-dev/reference/apis-arkui/native__interface_8h.md +++ b/zh-cn/application-dev/reference/apis-arkui/native__interface_8h.md @@ -30,7 +30,7 @@ | 名称 | 描述 | | -------- | -------- | -| [ArkUI_NativeAPIVariantKind](_ark_u_i___native_module.md#arkui_nativeapivariantkind) { ARKUI_NATIVE_NODE, ARKUI_NATIVE_DIALOG, ARKUI_NATIVE_GESTURE, ARKUI_NATIVE_ANIMATE } | 定义Native接口集合类型。 | +| [ArkUI_NativeAPIVariantKind](_ark_u_i___native_module.md#arkui_nativeapivariantkind) { ARKUI_NATIVE_NODE, ARKUI_NATIVE_DIALOG, ARKUI_NATIVE_GESTURE, ARKUI_NATIVE_ANIMATE, ARKUI_MULTI_THREAD_NATIVE_NODE } | 定义Native接口集合类型。 | ### 函数 diff --git a/zh-cn/application-dev/reference/apis-arkui/native__node_8h.md b/zh-cn/application-dev/reference/apis-arkui/native__node_8h.md index 69355a11915ed242fa8e341c402e762c58646398..d6b183c6aa3a2718085d9420eadea696dff97f7c 100644 --- a/zh-cn/application-dev/reference/apis-arkui/native__node_8h.md +++ b/zh-cn/application-dev/reference/apis-arkui/native__node_8h.md @@ -158,3 +158,7 @@ NODE_TEXT_AREA_HALF_LEADING = 8025, NODE_TEXT_AREA_KEYBOARD_APPEARANCE = 8026, N | int32_t [OH_ArkUI_NodeUtils_SetCrossLanguageOption](_ark_u_i___native_module.md#oh_arkui_nodeutils_setcrosslanguageoption)([ArkUI_NodeHandle](_ark_u_i___native_module.md#arkui_nodehandle) node, ArkUI_CrossLanguageOption* option) | 设置目标节点跨语言的配置。
**起始版本:** 15 | | int32_t [OH_ArkUI_NodeUtils_GetCrossLanguageOption](_ark_u_i___native_module.md#oh_arkui_nodeutils_getcrosslanguageoption)([ArkUI_NodeHandle](_ark_u_i___native_module.md#arkui_nodehandle) node, ArkUI_CrossLanguageOption* option) | 获取目标节点跨语言的配置。
**起始版本:** 15 | | int32_t [OH_ArkUI_NodeUtils_GetAttachedNodeHandleById](_ark_u_i___native_module.md#oh_arkui_nodeutils_getattachednodehandlebyid)(const char* id, [ArkUI_NodeHandle](_ark_u_i___native_module.md#arkui_nodehandle)* node) | 根据传入的id获取当前节点树上对应的目标节点。
**起始版本:** 15 | +| int32_t [OH_ArkUI_RunTaskInScope](_ark_u_i___native_module.md#oh_arkui_runtaskinscope)([ArkUI_ContextHandle](_ark_u_i___native_module.md#arkui_contexthandle-12) uiContext, void* userData, void(*callback)(void* userData)) | 在UIContext作用域内运行自定义函数。 | +| int32_t [OH_ArkUI_PostAsyncUITask](_ark_u_i___native_module.md#oh_arkui_postasyncuitask)([ArkUI_ContextHandle](_ark_u_i___native_module.md#arkui_contexthandle-12) uiContext, void* asyncUITaskData, void (*asyncUITask)(void* asyncUITaskData), void (*onFinish)(void* asyncUITaskData)) | 将UI任务抛到框架提供的非UI线程中执行 | +| int32_t [OH_ArkUI_PostUITask](_ark_u_i___native_module.md#oh_arkui_postuitask)([ArkUI_ContextHandle](_ark_u_i___native_module.md#arkui_contexthandle-12) uiContext, void* taskData, void (*task)(void* taskData)) | 将任务抛到UI线程中执行 | +| int32_t [OH_ArkUI_PostUITaskAndWait](_ark_u_i___native_module.md#oh_arkui_postuitaskandwait)([ArkUI_ContextHandle](_ark_u_i___native_module.md#arkui_contexthandle-12) uiContext, void* taskData, void (*task)(void* taskData)) | 将任务抛到UI线程中执行并阻塞等待 | diff --git a/zh-cn/application-dev/ui/ndk-build-on-multi-thread-api.md b/zh-cn/application-dev/ui/ndk-build-on-multi-thread-api.md new file mode 100644 index 0000000000000000000000000000000000000000..13d33f3faffa7408a8ab9593b2d1f1fca21b6c38 --- /dev/null +++ b/zh-cn/application-dev/ui/ndk-build-on-multi-thread-api.md @@ -0,0 +1,43 @@ +# 多线程NativeNode接口说明 +| 接口名 | 描述 | 非UI线程调用 | 规格 | +| -------- | ------- | ------- | ------- | +| ArkUI_NodeHandle (*createNode)(ArkUI_NodeType type) | 基于ArkUI_NodeType生成对应的组件并返回组件对象指针 | 支持 | 支持在任意线程调用 | +| void (*disposeNode)(ArkUI_NodeHandle node) | 销毁组件指针指向的对象 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*setAttribute)(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute, const ArkUI_AttributeItem* item) | 设置node节点的属性 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| const ArkUI_AttributeItem* (*getAttribute)(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute) | 获取node节点的属性 | 支持 | 在非UI线程操作不符合要求的node返回空指针 | +| int32_t (*resetAttribute)(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attribute) | 重置node节点的属性为默认值 | 支持 | 在非UI线程操作不符合要求的node错误码 | +| int32_t (*setLengthMetricUnit)(ArkUI_NodeHandle node, ArkUI_LengthMetricUnit unit) | 指定node节点的单位 | 支持 | 在非UI线程操作不符合要求的node错误码 | +| int32_t (*registerNodeEvent)(ArkUI_NodeHandle node, ArkUI_NodeEventType eventType, int32_t targetId, void* userData) | 向node节点注册事件 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| void (*unregisterNodeEvent)(ArkUI_NodeHandle node, ArkUI_NodeEventType eventType) | node节点解注册事件 | 支持 | 在非UI线程操作不符合要求的node接口调用无效 | +| int32_t (*registerNodeCustomEvent)(ArkUI_NodeHandle node, ArkUI_NodeCustomEventType eventType, int32_t targetId, void* userData) | 向node节点注册自定义事件 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| void (*unregisterNodeCustomEvent)(ArkUI_NodeHandle node, ArkUI_NodeCustomEventType eventType) | node节点解注册自定义事件 | 支持 | 在非UI线程操作不符合要求的node接口调用无效 | +| int32_t (*addNodeEventReceiver)(ArkUI_NodeHandle node, void (*eventReceiver)(ArkUI_NodeEvent* event)) | 向node节点注册事件回调函数,用于接收该组件产生的组件事件 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*removeNodeEventReceiver)(ArkUI_NodeHandle node, void (*eventReceiver)(ArkUI_NodeEvent* event)); | 删除node节点上注册的事件回调函数 | 支持 | 在在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*addNodeCustomEventReceiver)(ArkUI_NodeHandle node, void (*eventReceiver)(ArkUI_NodeCustomEvent* event)) | 向node节点注册自定义事件回调函数,用于接收该组件产生的自定义事件(如布局事件,绘制事件)。 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*removeNodeCustomEventReceiver)(ArkUI_NodeHandle node, void (*eventReceiver)(ArkUI_NodeCustomEvent* event)) | 删除node节点上注册的自定义事件回调函数 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*addChild)(ArkUI_NodeHandle parent, ArkUI_NodeHandle child) | 将child节点挂载到parent节点的子节点列表中 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| int32_t (*removeChild)(ArkUI_NodeHandle parent, ArkUI_NodeHandle child) | 将child节点从parent节点的子节点列表中移除 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| int32_t (*insertChildAfter)(ArkUI_NodeHandle parent, ArkUI_NodeHandle child, ArkUI_NodeHandle sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之后 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| int32_t (*insertChildBefore)(ArkUI_NodeHandle parent, ArkUI_NodeHandle child, ArkUI_NodeHandle sibling) | 将child节点挂载到parent节点的子节点列表中,挂载位置在sibling节点之前 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| int32_t (*insertChildAt)(ArkUI_NodeHandle parent, ArkUI_NodeHandle child, int32_t position) | 将child节点挂载到parent节点的子节点列表中,挂载位置由position指定 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| ArkUI_NodeHandle (*getParent)(ArkUI_NodeHandle node) | 获取node节点的父节点 | 支持 | 在非UI线程操作不符合要求的node返回错误码 | +| int32_t (*removeAllChildren)(ArkUI_NodeHandle parent) | 移除node节点的所有子节点 | 支持 | 在非UI线程操作不符合要求的parent返回错误码 | +| uint32_t (*getTotalChildCount)(ArkUI_NodeHandle node) | 获取node节点的子节点个数 | 支持 | 在非UI线程操作不符合要求的node接口返回0 | +| ArkUI_NodeHandle (*getChildAt)(ArkUI_NodeHandle node, int32_t position) | 获取node节点的子节点指针,位置由position指定 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| ArkUI_NodeHandle (*getFirstChild)(ArkUI_NodeHandle node) | 获取node节点的第一个子节点指针 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| ArkUI_NodeHandle (*getLastChild)(ArkUI_NodeHandle node) | 获取node节点的最后一个子节点指针 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| ArkUI_NodeHandle (*getPreviousSibling)(ArkUI_NodeHandle node) | 获取node节点的上一个兄弟节点指针 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| ArkUI_NodeHandle (*getNextSibling)(ArkUI_NodeHandle node) | 获取node节点的下一个兄弟节点指针针 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| int32_t (*setUserData)(ArkUI_NodeHandle node, void* userData) | 在node节点上保存自定义数据 | 支持 | 在非UI线程操作不符合要求的node接口返回错误码 | +| void* (*getUserData)(ArkUI_NodeHandle node) | 获取node节点上保存的自定义数据 | 支持 | 在非UI线程操作不符合要求的node接口返回空指针 | +| void (*registerNodeCustomEventReceiver)(void (*eventReceiver)(ArkUI_NodeCustomEvent* event)) | 注册节点自定义事件回调同一入口函数 | 不支持 | 只支持UI线程调用,否则接口调用无效 | +| void (*unregisterNodeCustomEventReceiver)() | 解注册节点自定义事件回调同一入口函数 | 不支持 | 只支持UI线程调用,否则接口调用无效 | +| void (*registerNodeEventReceiver)(void (*eventReceiver)(ArkUI_NodeEvent* event)) | 注册节点事件回调同一入口函数 | 不支持 | 只支持UI线程调用,否则接口调用无效 | +| void (*unregisterNodeEventReceiver)() | 解注册节点事件回调同一入口函数 | 不支持 | 只支持UI线程调用,否则接口调用无效 | +| int32_t (*setMeasuredSize)(ArkUI_NodeHandle node, int32_t width, int32_t height) | 在测算回调函数中设置组件测算完成后的宽和高 | 不支持 | 只支持UI线程调用,否则接口返回错误码 | +| int32_t (*setLayoutPosition)(ArkUI_NodeHandle node, int32_t positionX, int32_t positionY) | 在布局回调函数中设置组件的位置 | 不支持 | 只支持UI线程调用,否则接口返回错误码 | +| ArkUI_IntSize (*getMeasuredSize)(ArkUI_NodeHandle node) | 获取node节点测算完成后的宽高尺寸 | 不支持 | 只支持UI线程调用,否则接口返回默认值 | +| ArkUI_IntOffset (*getLayoutPosition)(ArkUI_NodeHandle node) | 获取node节点布局完成后的位置 | 不支持 | 只支持UI线程调用,否则接口返回默认值 | +| int32_t (*measureNode)(ArkUI_NodeHandle node, ArkUI_LayoutConstraint* Constraint) | 对node节点进行测算,可以通过getMeasuredSize获取测算后的大小 | 不支持 | 只支持UI线程调用,否则接口返回错误码 | +| int32_t (*layoutNode)(ArkUI_NodeHandle node, int32_t positionX, int32_t positionY) | 对node节点进行布局并传递该组件相对父组件的期望位置 | 不支持 | 只支持UI线程调用,否则接口返回错误码 | +| void (*markDirty)(ArkUI_NodeHandle node, ArkUI_NodeDirtyFlag dirtyFlag) | 强制标记node节点需要重新测算、布局或绘制 | 不支持 | 只支持UI线程调用,否则接口调用无效 | diff --git a/zh-cn/application-dev/ui/ndk-build-on-multi-thread.md b/zh-cn/application-dev/ui/ndk-build-on-multi-thread.md new file mode 100644 index 0000000000000000000000000000000000000000..f06c59500ef48955f192c990f4b31bb97b07616a --- /dev/null +++ b/zh-cn/application-dev/ui/ndk-build-on-multi-thread.md @@ -0,0 +1,216 @@ +# C-API 支持多线程创建组件 + +## 1. 概述 + +在旧版 C-API 中,组件的创建与初始化必须在应用程序主线程中执行。这一限制导致第三方框架开发者在集成时,不可避免地需要将自己的任务切换回主线程,不仅增加调用代码的复杂度,也限制了组件构造过程的灵活性与性能。 + +随着用户界面日益复杂,页面中可能同时存在大量动态生成的 UI 组件,这类任务堆积在单一主线程中执行,往往导致启动缓慢、动画掉帧以及界面卡顿,直接影响用户体验。 + +针对这些痛点,**新版 API 引入了完整的多线程支持**,为第三方框架开发者带来了以下实质性提升: + +- **彻底简化调用流程** 开发者再也无需手动切换线程或通过任务队列将组件创建任务转回主线程,而是可以在自己的框架线程中直接调用组件创建接口,减少上下文切换与潜在的竞态问题,简化框架与应用之间的交互逻辑。 + +- **性能与体验大幅优化** 多线程能力允许组件创建与初始化任务并行执行,能充分利用设备多核 CPU,在页面启动与界面构造阶段显著减少总体耗时。主线程则专注动画渲染与用户输入,不再因构造任务阻塞,保证界面流畅与交互及时。 + +- **为未来拓展奠定坚实基础** 多线程支持不仅解决当前性能瓶颈,也为后续引入更复杂、高负载的界面组件提供可扩展空间,帮助第三方框架开发者在设计时拥有更大的灵活度与掌控力,为持续提升用户体验创造条件。 + +通过这次升级,第三方框架开发者能专注于自身逻辑实现,不再为并发与线程切换等底层细节分心,也能在更大的任务量与复杂场景下获得更加可预测、高性能的界面创建体验。 + +## 2. 如何使用 + +- 调用 `OH_ArkUI_GetModuleInterface`,入参传入 `ARKUI_MULTI_THREAD_NATIVE_NODE` 获取支持多线程调用的 NDK 接口集合。例如: + + ```cpp + ArkUI_NativeNodeAPI_1 *multiThreadNodeAPI = nullptr; + OH_ArkUI_GetModuleInterface(ARKUI_MULTI_THREAD_NATIVE_NODE, ArkUI_NativeNodeAPI_1, multiThreadNodeAPI); + ``` + + 多线程接口详情请参考 [C-API 多线程接口](./ndk-build-on-multi-thread-api.md)。 + +- 也可以使用我们提供的接口,将任务调度到系统线程池中执行。例如: + + ```c + OH_ArkUI_PostAsyncUITask( + ArkUI_ContextHandle context, + void *asyncUITaskData, + void (*asyncUITask)(void *asyncUITaskData), + void (*onFinish)(void *asyncUITaskData) + ); + ``` + + **功能概述:** 该接口将任务 `asyncUITask` 抛到非 UI 线程执行,任务执行完毕后再调用 `onFinish` 在 UI 线程中执行。 + + **使用场景:** 开发者可使用此接口在非 UI 线程中创建组件,完成后回 UI 线程将其挂载到主树上。 + + 另提供以下接口: + + ```c + OH_ArkUI_PostUITask(ArkUI_ContextHandle context, void* taskData, void(*task)(void* taskData)); + ``` + + 用于将任务抛给 UI 线程执行。 + + ```c + OH_ArkUI_PostUITaskAndWait(ArkUI_ContextHandle context, void* taskData, void(*task)(void* taskData)); + ``` + + 用于将任务抛给 UI 线程执行,并等待任务结束,**使用限制**是可能导致非 UI 线程长时间阻塞,不推荐频繁使用。 + +## 3. 调用规范与线程安全 + +- 多线程接口规范请参考 [C-API 多线程接口](./ndk-build-on-multi-thread-api.md)。调用接口时必须检查返回值,在非 UI 线程中调用不支持的接口将返回错误码。 + +- 尽管我们提供了线程安全的组件创建与属性设置接口,单个组件内部仍然不是线程安全的,不允许在多个线程中同时操作同一组件,否则可能出现不可预测的结果。 + +- 多线程接口中,组件有两种状态: + + - **Free(游离状态):** 组件尚未挂载到主树,不参与 UI 流水线,属性可安全更新。 + - **Attached(已挂载状态):** 组件已挂载,交由 UI 渲染流水线管理,此时属性更新必须在 UI 线程中调用,否则将返回错误码。 + +## 4. 示例代码 + +以下是接口使用示例: + +- index.ets + +``` +import { NodeContent } from '@kit.ArkUI'; +import entry from 'libentry.so'; + +@Entry +@Component +struct Index { + private rootSlot = new NodeContent(); + + aboutToAppear(): void { + // 调用C接口进行组件创建 + entry.CreateNodeTreeOnMultiThread(this.rootSlot, this.getUIContext()); + } + + build() { + Flex() { + Column() { + Text('CreateNodeTreeOnMultiThread') + .fontSize(18) + .fontWeight(FontWeight.Bold) + // C-API组件挂载点 + ContentSlot(this.rootSlot) + } + } + } +} + +``` + +- example.c + +``` +#include +#include +#include + +#define CHILD_NODE_TREE_NUMBER 10 +struct AsyncData { + ArkUI_NodeHandle parent = nullptr; + ArkUI_NodeHandle child = nullptr; +}; +// 多线程的组件创建接口 +void CreateNodeTree(void *asyncUITaskData) { + ArkUI_NativeNodeAPI_1 *multiThreadNodeAPI = nullptr; + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, multiThreadNodeAPI); + auto asyncData = static_cast(asyncUITaskData); + if (!multiThreadNodeAPI || !asyncData) { + return; + } + asyncData->child = multiThreadNodeAPI->createNode(ARKUI_NODE_ROW); + + auto button1 = multiThreadNodeAPI->createNode(ARKUI_NODE_BUTTON); + ArkUI_AttributeItem label_item = { .string = "button1" }; + multiThreadNodeAPI->setAttribute(button1, NODE_BUTTON_LABEL, &label_item); + + auto button2 = multiThreadNodeAPI->createNode(ARKUI_NODE_BUTTON); + ArkUI_AttributeItem label_item2 = { .string = "button2" }; + multiThreadNodeAPI->setAttribute(button2, NODE_BUTTON_LABEL, &label_item2); + + multiThreadNodeAPI->addChild(asyncData->child, button1); + multiThreadNodeAPI->addChild(asyncData->child, button2); +} +// 组件多线程创建完成后,回到主线程挂载 +void MountNodeTree(void *asyncUITaskData) { + ArkUI_NativeNodeAPI_1 *multiThreadNodeAPI = nullptr; + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, multiThreadNodeAPI); + auto asyncData = static_cast(asyncUITaskData); + if (!multiThreadNodeAPI || !asyncData) { + delete asyncData; + return; + } + auto parent = asyncData->parent; + auto child = asyncData->child; + multiThreadNodeAPI->addChild(parent, child); + delete asyncData; +} + +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); + + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + ArkUI_ContextHandle contextHandle; + OH_ArkUI_GetContextFromNapiValue(env, args[1], &contextHandle); + + ArkUI_NativeNodeAPI_1 *nodeAPI = nullptr; + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + if (!nodeAPI) { + return nullptr; + } + auto scroll = nodeAPI->createNode(ARKUI_NODE_SCROLL); + if (OH_ArkUI_NodeContent_AddNode(contentHandle, scroll) != 0) { + return nullptr; + } + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + nodeAPI->addChild(scroll, column); + + for (int i = 0; i < CHILD_NODE_TREE_NUMBER; i++) { + //UI线程创建子树根节点,保证scroll的子节点顺序 + auto columnItem = nodeAPI->createNode(ARKUI_NODE_COLUMN); + nodeAPI->addChild(column, columnItem); + AsyncData* asyncData = new AsyncData(); + asyncData->parent = columnItem; + // 在非UI线程创建组件树,创建完成后回到主线程挂载到主树上 + if (OH_ArkUI_PostAsyncUITask(contextHandle, asyncData, CreateNodeTree, MountNodeTree) != 0) { + delete asyncData; + } + } + return nullptr; +} +``` + +## 5. 错误与异常处理 + +- 在非 UI 线程中调用不支持多线程调用的接口将返回错误码。 +- 挂载到 UI 主树后,非 UI 线程中调用组件接口将返回错误码。 +- 对于 C-API 节点中嵌套 ArkTS 节点的情况,必须在 C-API 节点下树前先卸载 ArkTS 节点,以避免在非 UI 线程中遍历节点树时访问 ArkTS 节点导致崩溃。 + +框架将打印如下日志提示: + +``` +CheckIsThreadSafeNodeTree failed. thread safe node tree contains unsafe node: ${nodeid} +``` + +## 6. 迁移指南 + +1. 将原有接口集合 Tag 从 `ARKUI_NATIVE_NODE` 修改为 `ARKUI_MULTI_THREAD_NATIVE_NODE` 即可获得多线程能力,接口与参数保持一致: + + ```c + ArkUI_NativeNodeAPI_1 *nodeAPI = nullptr; + OH_ArkUI_GetModuleInterface(ARKUI_MULTI_THREAD_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + ``` + +2. 建议将原先在 UI 线程中执行的组件创建任务拆分成更细粒度任务,分派给不同工作线程执行,以减少主线程阻塞,提高页面启动与更新流畅度。 + +3. 预先在后台线程中创建常用组件树,为性能敏感场景提供更好的用户体验。 + +## 最佳实践 +通过以下的一个例子,我们将展示如何通过多线程的C-API接口来实现并行化创建组建,最终提升用户体验。 \ No newline at end of file