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 ```