• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArkTS多线程间操作Native对象场景
2
3在ArkTS应用开发中,有很多场景需要将ArkTS对象与Native对象进行绑定。ArkTS对象将数据写入Native对象,Native对象再将数据写入目的地。例如,将ArkTS对象中的数据写入C++数据库场景。
4
5本示例将详细说明如何利用ArkTS对象执行对Native对象数据的存储、删除和清空等操作。
6
71. Naitve实现各项功能。
8
9   ```cpp
10   // napi_init.cpp
11   #include <bits/alltypes.h>
12   #include <hilog/log.h>
13   #include <mutex>
14   #include <unordered_set>
15   #include <uv.h>
16   #include "napi/native_api.h"
17
18   class Object {
19   public:
20       Object() = default;
21       ~Object() = default;
22
23       static Object* GetInstance()
24       {
25           Object* instance = new Object();
26           return instance;
27       }
28
29       static napi_value GetAddress(napi_env env, napi_callback_info info)
30       {
31           napi_value thisVar = nullptr;
32           napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
33           if (thisVar == nullptr) {
34               return nullptr;
35           }
36           void* object = nullptr;
37           napi_unwrap(env, thisVar, &object);
38           if (object == nullptr) {
39               return nullptr;
40           }
41           uint64_t addressVal = reinterpret_cast<uint64_t>(object);
42           napi_value address = nullptr;
43           napi_create_bigint_uint64(env, addressVal, &address);
44           return address;
45       }
46
47       // 获取数组大小
48       static napi_value GetSetSize(napi_env env, napi_callback_info info)
49       {
50           napi_value thisVar = nullptr;
51           napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
52           if (thisVar == nullptr) {
53               return nullptr;
54           }
55           void* object = nullptr;
56           napi_unwrap(env, thisVar, &object);
57           if (object == nullptr) {
58               return nullptr;
59           }
60           std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
61           uint32_t setSize = reinterpret_cast<Object*>(object)->numberSet_.size();
62           napi_value napiSize = nullptr;
63           napi_create_uint32(env, setSize, &napiSize);
64           return napiSize;
65       }
66
67       // 往数组里插入元素
68       static napi_value Store(napi_env env, napi_callback_info info)
69       {
70           size_t argc = 1;
71           napi_value args[1] = {nullptr};
72           napi_value thisVar = nullptr;
73           napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
74           if (argc != 1) {
75               napi_throw_error(env, nullptr, "Store args number must be one.");
76               return nullptr;
77           }
78           napi_valuetype type = napi_undefined;
79           napi_typeof(env, args[0], &type);
80           if (type != napi_number) {
81               napi_throw_error(env, nullptr, "Store args is not number.");
82               return nullptr;
83           }
84           if (thisVar == nullptr) {
85               return nullptr;
86           }
87           uint32_t value = 0;
88           napi_get_value_uint32(env, args[0], &value);
89           void* object = nullptr;
90           napi_unwrap(env, thisVar, &object);
91           if (object == nullptr) {
92               return nullptr;
93           }
94           std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
95           reinterpret_cast<Object *>(object)-> numberSet_.insert(value);
96           return nullptr;
97       }
98
99       // 删除数组元素
100       static napi_value Erase(napi_env env, napi_callback_info info)
101       {
102           size_t argc = 1;
103           napi_value args[1] = {nullptr};
104           napi_value thisVar = nullptr;
105           napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
106           if (argc != 1) {
107               napi_throw_error(env, nullptr, "Erase args number must be one.");
108               return nullptr;
109           }
110           napi_valuetype type = napi_undefined;
111           napi_typeof(env, args[0], &type);
112           if (type != napi_number) {
113               napi_throw_error(env, nullptr, "Erase args is not number.");
114               return nullptr;
115           }
116           if (thisVar == nullptr) {
117               return nullptr;
118           }
119           uint32_t value = 0;
120           napi_get_value_uint32(env, args[0], &value);
121           void* object = nullptr;
122           napi_unwrap(env, thisVar, &object);
123           if (object == nullptr) {
124               return nullptr;
125           }
126           std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
127           reinterpret_cast<Object *>(object)->numberSet_.erase(value);
128           return nullptr;
129       }
130
131       // 清空数组
132       static napi_value Clear(napi_env env, napi_callback_info info)
133       {
134           napi_value thisVar = nullptr;
135           napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
136           if (thisVar == nullptr) {
137               return nullptr;
138           }
139           void* object = nullptr;
140           napi_unwrap(env, thisVar, &object);
141           if (object == nullptr) {
142               return nullptr;
143           }
144           std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
145           reinterpret_cast<Object *>(object)->numberSet_.clear();
146           return nullptr;
147       }
148
149   private:
150       Object(const Object &) = delete;
151       Object &operator=(const Object &) = delete;
152
153       std::unordered_set<uint32_t> numberSet_{};
154       std::mutex numberSetMutex_{};
155   };
156
157   void FinializerCallback(napi_env env, void *data, void *hint)
158   {
159       return;
160   }
161
162   // 解绑回调,在序列化时调用,可在对象解绑时执行一些清理操作
163   void* DetachCallback(napi_env env, void *value, void *hint)
164   {
165       return value;
166   }
167
168   // 绑定回调,在反序列化时调用
169   napi_value AttachCallback(napi_env env, void* value, void* hint)
170   {
171       napi_value object = nullptr;
172       napi_create_object(env, &object);
173       napi_property_descriptor desc[] = {
174           {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
175           {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
176           {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
177           {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
178           {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
179       napi_define_properties(env, object, sizeof(desc) / sizeof(desc[0]), desc);
180       // 将JS对象object和native对象value生命周期进行绑定
181       napi_status status = napi_wrap(env, object, value, FinializerCallback, nullptr, nullptr);
182       if (status != napi_ok) {
183           // 根据业务需要做异常处理
184       }
185       // JS对象携带native信息
186       napi_coerce_to_native_binding_object(env, object, DetachCallback, AttachCallback, value, hint);
187       return object;
188   }
189
190   EXTERN_C_START
191   static napi_value Init(napi_env env, napi_value exports)
192   {
193       napi_property_descriptor desc[] = {
194           {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
195           {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
196           {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
197           {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
198           {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
199       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
200       auto object = Object::GetInstance();
201       napi_status status = napi_wrap(env, exports, reinterpret_cast<void*>(object), FinializerCallback, nullptr, nullptr);
202       if (status != napi_ok) {
203           delete object;
204       }
205       napi_coerce_to_native_binding_object(env, exports, DetachCallback, AttachCallback, reinterpret_cast<void*>(object),
206                                            nullptr);
207       return exports;
208   }
209   EXTERN_C_END
210
211   static napi_module demoModule = {
212       .nm_version = 1,
213       .nm_flags = 0,
214       .nm_filename = nullptr,
215       .nm_register_func = Init,
216       .nm_modname = "entry",
217       .nm_priv = ((void*)0),
218       .reserved = { 0 },
219   };
220
221   extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
222   {
223       napi_module_register(&demoModule);
224   }
225   ```
226
227
2282. 在ArkTS中声明接口。
229
230   ```ts
231   // index.d.ts
232   export const getAddress: () => number;
233   export const getSetSize: () => number;
234   export const store: (a: number) => void;
235   export const erase: (a: number) => void;
236   export const clear: () => void;
237   ```
238
2393. ArkTS对象调用Native侧实现的各项功能。
240
241   ```ts
242   // index.ets
243   import testNapi from 'libentry.so';
244   import { taskpool } from '@kit.ArkTS';
245
246   @Concurrent
247   function getAddress() {
248     let address: number = testNapi.getAddress();
249     console.info("taskpool:: address is " + address);
250   }
251
252   @Concurrent
253   function store(a:number, b:number, c:number) {
254     let size:number = testNapi.getSetSize();
255     console.info("set size is " + size + " before store");
256     testNapi.store(a);
257     testNapi.store(b);
258     testNapi.store(c);
259     size = testNapi.getSetSize();
260     console.info("set size is " + size + " after store");
261   }
262
263   @Concurrent
264   function erase(a:number) {
265     let size:number = testNapi.getSetSize();
266     console.info("set size is " + size + " before erase");
267     testNapi.erase(a);
268     size = testNapi.getSetSize();
269     console.info("set size is " + size + " after erase");
270   }
271
272   @Concurrent
273   function clear() {
274     let size:number = testNapi.getSetSize();
275     console.info("set size is " + size + " before clear");
276     testNapi.clear();
277     size = testNapi.getSetSize();
278     console.info("set size is " + size + " after clear");
279   }
280
281   async function test(): Promise<void> {
282       let address:number = testNapi.getAddress();
283       console.info("host thread address is " + address);
284
285       let task1 = new taskpool.Task(getAddress);
286       await taskpool.execute(task1);
287
288       let task2 = new taskpool.Task(store, 1, 2, 3);
289       await taskpool.execute(task2);
290
291       let task3 = new taskpool.Task(store, 4, 5, 6);
292       await taskpool.execute(task3);
293
294       let task4 = new taskpool.Task(erase, 3);
295       await taskpool.execute(task4);
296
297       let task5 = new taskpool.Task(erase, 5);
298       await taskpool.execute(task5);
299
300       let task6 = new taskpool.Task(clear);
301       await taskpool.execute(task6);
302   }
303
304   @Entry
305   @Component
306   struct Index {
307     @State message: string = 'Hello World';
308
309     build() {
310       Row() {
311         Column() {
312           Text(this.message)
313             .fontSize($r('app.float.page_text_font_size'))
314             .fontWeight(FontWeight.Bold)
315             .onClick(() => {
316               test();
317             })
318         }
319         .width('100%')
320       }
321       .height('100%')
322     }
323   }
324   ```