HarmonyOS 鸿蒙Next Native如何在异步线程里安全回调到ArkTs线程中

如下: ArkTS层:指鸿蒙的上层代码,

用ArkTS实现 Native:基于鸿蒙的N-API实现的C++代码,用于调用我们自己的SO库 SO库:用c语言实现的跨端so库。

  1. 整体调用链路 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

2 回复

可以通过以下方法在异步线程中安全回调到ArkTS线程:

1.使用napi_call_threadsafe_function_with_priority:

可以使用Node-API中的napi_call_threadsafe_function_with_priority接口从异步线程向ArkTS线程投递任务 。该接口允许指定任务的优先级和入队方式。

参考示例:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/use-call-threadsafe-function-with-priority-V5

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线程执行。具体操作步骤如下:

  1. 获取UI线程的Dispatcher:通过ArkTs框架提供的API获取UI线程的调度器(Dispatcher)。

  2. 封装回调任务:将要回调到UI线程执行的任务封装成一个Runnable或Callable对象。

  3. 使用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

回到顶部