HarmonyOS 鸿蒙Next Native如何在异步线程里安全回调到ArkTs线程中
如下: ArkTS层:指鸿蒙的上层代码,
用ArkTS实现 Native:基于鸿蒙的N-API实现的C++代码,用于调用我们自己的SO库 SO库:用c语言实现的跨端so库。
- 整体调用链路 ArkTS层有一个callback函数,执行start函数。start函数调用到Native层。 这个时候Native要到调用到我们自己一个so库,so库会产生一个异步线程做内部做音频评测,然后从so库的异步线程回调到Native层,我们再通过
napi_value
async_resource_name;
napi_create_string_utf8(global_env, "AsyncTask", NAPI_AUTO_LENGTH, & async_resource_name
);
napi_async_work
work;
napi_create_async_work(global_env, nullptr, async_resource_name, ExecuteWork, CompleteWork, nullptr, & work
);
napi_queue_async_work(global_env, work);
下面的代码把结果回调回ArkTS的主线程,主要的回调是在CompleteWork完成的
2、实时录音导致的线程安全问题 我们是录音实时回调到Native再回到C层的子线程执行评测,再通过上面的
napi_value
async_resource_name;
napi_create_string_utf8(global_env, "AsyncTask", NAPI_AUTO_LENGTH, & async_resource_name
);
napi_async_work
work;
napi_create_async_work(global_env, nullptr, async_resource_name, ExecuteWork, CompleteWork, nullptr, & work
);
napi_queue_async_work(global_env, work);
回调到ArkTS层,所以调用的次数会很多,存在线程问题
3、我们目前技术需求:
3.1 我们主要需要等待SO库的子线程回调,才能把结果返回ArkTS层,因此需要一个在Native的子线程里可以安全回调ArkTS层的技术方案。
更多关于HarmonyOS 鸿蒙Next Native如何在异步线程里安全回调到ArkTs线程中的实战教程也可以访问 https://www.itying.com/category-93-b0.html
可以通过以下方法在异步线程中安全回调到ArkTS线程:
1.使用napi_call_threadsafe_function_with_priority:
可以使用Node-API中的napi_call_threadsafe_function_with_priority接口从异步线程向ArkTS线程投递任务 。该接口允许指定任务的优先级和入队方式。
2.使用libuv异步库:
在C++层建立的子线程中,通过调用libuv接口(如uv_queue_work)抛ArkTS任务到loop中执行。
3.在非ArkTS线程中回调ArkTS接口:
通过napi_get_uv_event_loop获取env对应的loop,并抛任务到ArkTS线程 。
我们这边没有so可以调用,外部so引入参考链接:
https://gitee.com/openharmony-sig/tpc_c_cplusplus/blob/master/lycium/doc/app_calls_third_lib.md
以下是异步线程调用参考代码
struct ArkCallNativeData {
napi_async_work asyn_work = nullptr;
napi_ref callbackRef = nullptr; // 延长函数的生命周期
double a = 0;
double b = 0;
double result = 0;
};
static void AysncExcuteCB(napi_env env, void *data) {
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkCallNative", "AysncExcuteCB>>>>>>>>>>>>>>>");
ArkCallNativeData *callBack = reinterpret_cast<ArkCallNativeData *>(data);
callBack->result = callBack->a + callBack->b;
//此处10s 模拟耗时任务,可在这里调用你的耗时so任务
std::this_thread::sleep_for(std::chrono::seconds(10));
}
static void AsyncCompeleCB(napi_env env, napi_status status, void *data) {
ArkCallNativeData *callBackData = reinterpret_cast<ArkCallNativeData *>(data);
napi_value callBackArg[1] = {nullptr};
// 创建返回参数
napi_create_double(env, callBackData->result, &callBackArg[0]);
// 获取回调函数
napi_value callback = nullptr;
// 获取回调函数保存的引用
napi_get_reference_value(env, callBackData->callbackRef, &callback);
// 执行回调函数
napi_value result;
napi_value undefined;
napi_get_undefined(env, &undefined);
//此处回调您的so结果
napi_call_function(env, undefined, callback, 1, callBackArg, &result);
// 删除异步任务和回调
napi_delete_reference(env, callBackData->callbackRef);
napi_delete_async_work(env, callBackData->asyn_work);
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkCallNative", "AsyncCompeleCB>>>>>>>>>>>>>>>");
delete callBackData;
}
/**
* 异步调用
* @param env
* @param info
* @return
*/
static napi_value ArkAsyncCallNatvieFunc(napi_env env, napi_callback_info info) {
size_t argc = 3;
napi_value args[3] = {nullptr};
// 获取参数
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
auto asynContext = new ArkCallNativeData();
// 保存参数到CallBack
double args1 = 0;
napi_get_value_double(env, args[0], &asynContext->a);
napi_get_value_double(env, args[1], &asynContext->b);
// 保存函数引用 将传入的cb函数 转换为napi_ref 延长生命周期 ====Mark
napi_create_reference(env, args[2], 1, &asynContext->callbackRef);
napi_value resourceName;
napi_create_string_utf8(env, "ArkAsyncCallNatvieFunc", NAPI_AUTO_LENGTH, &resourceName);
// 创建异步线程函数
napi_create_async_work(env, nullptr, resourceName, AysncExcuteCB, AsyncCompeleCB, asynContext,
&asynContext->asyn_work);
// 加入队列
napi_queue_async_work(env, asynContext->asyn_work);
return nullptr;
}
arkts侧函数声明
export const arkAsyncCallNatvieFunc: (a: number, b: number, cb: (res: number) => void) => void
更多关于HarmonyOS 鸿蒙Next Native如何在异步线程里安全回调到ArkTs线程中的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next Native环境中,若需要在异步线程中安全回调到ArkTs(Ark UI的TypeScript框架)线程中,你可以使用PostTask
机制来确保线程间通信的安全性。
ArkTs框架提供了与UI线程通信的接口,允许你在非UI线程中通过PostTask
将任务投递到UI线程执行。具体操作步骤如下:
-
获取UI线程的Dispatcher:通过ArkTs框架提供的API获取UI线程的调度器(Dispatcher)。
-
封装回调任务:将要回调到UI线程执行的任务封装成一个Runnable或Callable对象。
-
使用PostTask投递任务:调用Dispatcher的
PostTask
方法,将封装好的任务投递到UI线程执行。
示例代码(伪代码):
// 假设已经获取了UI线程的Dispatcher
auto dispatcher = GetUIDispatcher();
// 封装回调任务
auto task = []() {
// 执行UI相关操作
};
// 投递任务到UI线程
dispatcher->PostTask(task);
确保在异步线程中正确获取和使用UI线程的Dispatcher,可以有效避免线程间通信的问题。如果任务执行涉及复杂逻辑或资源管理,还需考虑线程安全和资源释放等问题。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html