• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 在非ArkTS线程中回调ArkTS接口
2
3## 场景介绍
4
5ArkTS是单线程语言,通过NAPI接口对ArkTS对象的所有操作都须保证在同一个ArkTS线程上进行。本示例将介绍通过`napi_get_uv_event_loop`和`uv_queue_work`实现在非ArkTS线程中通过NAPI接口回调ArkTS函数。
6
7## 使用示例
8
91. 接口声明、编译配置以及模块注册
10
11   **接口声明**
12
13   ```ts
14   // index.d.ts
15   export const queueWork: (cb: (arg: number) => void) => void;
16   ```
17
18   **编译配置**
19
20   ```
21   // CMakeLists.txt
22   # the minimum version of CMake.
23   cmake_minimum_required(VERSION 3.4.1)
24   project(MyApplication)
25
26   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
27
28   include_directories(${NATIVERENDER_ROOT_PATH}
29                       ${NATIVERENDER_ROOT_PATH}/include)
30   add_library(queue_work SHARED queue_work.cpp)
31   target_link_libraries(queue_work PUBLIC libace_napi.z.so libhilog_ndk.z.so libuv.so)
32   ```
33
34   **模块注册**
35
36   ```cpp
37   // queue_work.cpp
38   EXTERN_C_START
39   static napi_value Init(napi_env env, napi_value exports)
40   {
41       napi_property_descriptor desc[] = {
42           { "queueWork", nullptr, QueueWork, nullptr, nullptr, nullptr, napi_default, nullptr }
43       };
44       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
45       return exports;
46   }
47   EXTERN_C_END
48
49   static napi_module nativeModule = {
50       .nm_version = 1,
51       .nm_flags = 0,
52       .nm_filename = nullptr,
53       .nm_register_func = Init,
54       .nm_modname = "queue_work",
55       .nm_priv = nullptr,
56       .reserved = { 0 },
57   };
58
59   extern "C" __attribute__((constructor)) void RegisterQueueWorkModule()
60   {
61       napi_module_register(&nativeModule);
62   }
63   ```
64
652. 获取env对应的loop,并抛任务到ArkTS线程
66
67   ```cpp
68   // queue_work.cpp
69   #include <thread>
70
71   #include "napi/native_api.h"
72   #include "uv.h"
73
74   struct CallbackContext {
75       napi_env env = nullptr;
76       napi_ref callbackRef = nullptr;
77       int32_t retData = 0;
78   };
79
80   void StartThread(CallbackContext* context)
81   {
82       // 从env中获取对应的ArkTS线程的loop,此处的env需要在注册JS回调时保存下来。
83       uv_loop_s* loop = nullptr;
84       napi_get_uv_event_loop(context->env, &loop);
85
86       // 创建uv_work_t用于传递私有数据,注意回调完成后需要释放内存,此处省略生成回传数据的逻辑,传回int类型1。
87       uv_work_t* work = new uv_work_t;
88       context->retData = 1;
89       work->data = context;
90
91       // 抛任务到ArkTS线程
92       uv_queue_work(
93           loop,
94           work,
95           // work_cb 此回调在另一个普通线程中执行,用于处理异步或者耗时任务,回调执行完后执行下面的回调。本示例中无需执行任务。
96           [](uv_work_t* work) {},
97           // after_work_cb 此回调在env对应的ArkTS线程中执行。
98           [](uv_work_t* work, int status) {
99               CallbackContext* context = reinterpret_cast<CallbackContext*>(work->data);
100               napi_handle_scope scope = nullptr;
101               // 打开handle scope用于管理napi_value的生命周期,否则会内存泄露。
102               napi_open_handle_scope(context->env, &scope);
103               if (scope == nullptr) {
104                   return;
105               }
106
107               // 回调ArkTS函数
108               napi_value callback = nullptr;
109               napi_get_reference_value(context->env, context->callbackRef, &callback);
110               napi_value retArg;
111               napi_create_int32(context->env, context->retData, &retArg);
112               napi_value ret;
113               napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret);
114               napi_delete_reference(context->env, context->callbackRef);
115
116               // 关闭handle scope释放napi_value
117               napi_close_handle_scope(context->env, scope);
118
119               if (work != nullptr) {
120                   delete work;
121               }
122               delete context;
123           }
124       );
125   }
126
127   static napi_value QueueWork(napi_env env, napi_callback_info info)
128   {
129       size_t argc = 1;
130       napi_value argv[1] = {nullptr};
131       napi_value thisVar = nullptr;
132       void *data = nullptr;
133       napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
134
135       // 参数检查
136       if (argc < 1) {
137           napi_throw_error(env, "ParameterError", "one param expected");
138           return nullptr;
139       }
140       napi_valuetype valueType = napi_undefined;
141       napi_typeof(env, argv[0], &valueType);
142       if (valueType != napi_function) {
143           napi_throw_error(env, "ParameterError", "function expected");
144           return nullptr;
145       }
146
147       // 保存env和回调函数,以便后续回调
148       auto asyncContext = new CallbackContext();
149       asyncContext->env = env;
150       napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef);
151       // 模拟抛到非js线程执行逻辑
152       std::thread testThread(StartThread, asyncContext);
153       testThread.detach();
154
155       return nullptr;
156   }
157   ```
158
1593. ArkTS侧示例代码
160
161   ```ts
162   import { queueWork }  from 'libqueue_work.so'
163
164   queueWork((result: number) => {
165       console.log("result = " + result);
166   });
167   ```
168