仓颉多线程中使用互操作库
ArkTS 是单线程执行的虚拟机,在运行时上没有对并发做任何的容错;而仓颉在语法上支持内存共享的多线程。
如果在互操作的场景中不加限制地使用多线程,可能会导致无法预期的错误,因此需要一些规范和指引来保证程序正常执行:
- ArkTS 代码以及大部分互操作接口只能在 ArkTS 线程上执行,否则会抛出仓颉异常。
- 在进入其他线程前,需要把所有依赖的 ArkTS 数据转换为仓颉数据。
- 在其他线程如果想要使用 ArkTS 接口,需要通过
context.postJSTask切换到 ArkTS 线程来执行。
下面通过一个用例来展示具体做法。该用例为一个互操作函数,其功能是对两个数字相加,并调用回调函数返回相加结果。
-
定义仓颉函数:
package ohos_app_cangjie_entry import ohos.ark_interop.* // 类名没有影响 class Main { // 定义静态构造函数 static init() { // 注册键值对 JSModule.registerFunc("addNumberAsync", addNumberAsync) } } func addNumberAsync(context: JSContext, callInfo: JSCallInfo): JSValue { // 从 JSCallInfo 获取参数列表 let arg0: JSValue = callInfo[0] let arg1: JSValue = callInfo[1] let arg2: JSValue = callInfo[2] // 把 JSValue 转换为仓颉类型 let a: Float64 = arg0.toNumber() let b: Float64 = arg1.toNumber() let callback = arg2.asFunction() // 新建仓颉线程 spawn { // 实际仓颉函数行为 let value = a + b // 发起异步回调 context.postJSTask { // 创建 result let result = context.number(value).toJSValue() // 调用 js 回调 callback.call(result) } } // 返回 void return context.undefined().toJSValue() } -
在 Index.d.ts 文件中,提供互操作的接口声明:
// libohos_app_cangjie_entry.so 对应的 Index.d.ts export declare function addNumberAsync(a: number, b: number, callback: (result: number) => void): void; -
ArkTS 调用仓颉函数:
// 导入仓颉动态库,该动态库名称为仓颉包名的名称,该名称需要和互操作接口所在的包名一致 import { addNumberAsync } from "libohos_app_cangjie_entry.so"; // 调用仓颉函数 addNumberAsync(1, 2, (result) => { console.log("1 + 2 = " + result); });
在 ArkTS 中存在 Promise,这是对回调机制的一种封装,配合 async、await 的语法让回调机制变成同步调用的形式。对于上一个用例,可以使用 Promise 的形式来定义接口和访问:
-
定义仓颉函数:
package ohos_app_cangjie_entry import ohos.ark_interop.* // 类名没有影响 class Main { // 定义静态构造函数 static init() { // 注册键值对 JSModule.registerFunc("addNumberAsync", addNumberAsync) } } // 接口定义 func addNumberAsync(context: JSContext, callInfo: JSCallInfo): JSValue { // 参数转换为仓颉类型 let a = callInfo[0].toNumber() let b = callInfo[1].toNumber() // 创建 PromiseCapability 对象 let promise = context.promiseCapability() // 创建新线程 spawn { // 在新线程执行仓颉逻辑 let result = a + b // 切换到 ArkTS 线程 context.postJSTask { // 在 ArkTS 线程执行 resolve promise.resolve(context.number(result).toJSValue()) } } // 返回 Promise promise.toJSValue() } -
在 Index.d.ts 文件中,提供互操作的接口声明:
// libohos_app_cangjie_entry.so 对应的 Index.d.ts export declare function addNumberAsync(a: number, b: number): Promise<number>; -
ArkTS 调用仓颉函数:
// 导入仓颉动态库,该动态库名称为仓颉包名的名称,该名称需要和互操作接口所在的包名一致 import { addNumberAsync } from "libohos_app_cangjie_entry.so"; async function call() { // 调用仓颉函数 let result = await addNumberAsync(1, 2); console.log("1 + 2 = " + result); } call();