介绍

本示例主要介绍在TaskPool子线程中使用 dlopen 预加载 so 库并使用句柄调用库函数的方法,以及在Native中使用 pread 系统函数读取Rawfile文件的部分文本内容,并添加 HiLog 日志。

效果图预览

使用说明

  1. rawfile路径下存在一个有内容的文本文件rawfile.txt。
  2. 输入开始读取位置、需要读取的长度,点击“开始读取”,即可通过调用Native侧暴露的getRawFileContent接口把读取到的内容显示在界面上。

具体代码可参考MainPage.ets。

实现思路

在TaskPool子线程中使用dlopen预加载so库和使用句柄调用so库函数的方式

  1. 将需要加载的.so文件放到工程中,在CMakeLists中使用target_link_directories命令将包含这些库文件的目录添加到预加载库的链接目录。
target_link_directories(preloadso PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/
  1. 使用target_link_libraries命令将需要预加载的so库链接到项目中。
target_link_libraries(preloadso PUBLIC libhilog_ndk.z.so libace_napi.z.so global_handlers libnativerawfile.so)
  1. 定义一个全局对象global_handlers用于存放加载so库所得句柄,其他需要使用global_handlers的cpp文件需要引入定义全局对象的头文件。
std::unordered_map<std::string, void *> global_handlers;
  1. 在 Native 层的 Preload 接口中,遍历传入的 .so 路径数组,使用 dlopen 函数加载库,并将句柄保存到 global_handlers 中。
// 获取传入的so库路径数组的长度
uint32_t arrayLength;
napi_get_array_length(env, args[0], &arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
napi_get_element(env, args[0], i, &pathString); // 获取数组的第 i 个元素
napi_status status = napi_get_value_string_utf8(env, pathString, path, sizeof(path), &pathLength);
if (status != napi_ok) {
// 处理获取路径失败的情况
continue;
}
// TODO:知识点:使用dlopen动态加载so库,返回so库的句柄
void *handler = dlopen(path, RTLD_LAZY);
if (handler == nullptr) {
// TODO:知识点:dlerror抛出加载库失败的错误
dlerror();
continue; // 加载下一个
}
// 将句柄保存到全局对象global_handlers中
global_handlers[std::string(path)] = handler;
}
  1. 暴露Preload接口给ArkTS层使用,使其能够通过preload调用Native层的Preload接口。
napi_property_descriptor desc[] = {{"preload", nullptr, Preload, nullptr, nullptr, nullptr, napi_default, nullptr}};
  1. ArkTS层使用TaskPool创建子线程,通过preload接口调用Native侧的Preload接口,实现在TaskPool子线程中加载.so库,导出preloadSOByTaskPool函数。
@Concurrent
function preloadSO(): string[] {
return napi.preload(Constants.LIBRARY_PATH_ARRAY);
}
export function preloadSOByTaskPool(): void {
// TODO: 知识点:使用new taskpool.Task()创建任务项,传入任务执行函数和所需参数
let task: taskpool.Task = new taskpool.Task(preloadSO);
try {
// TODO:知识点:使用taskpool.execute将待执行的函数放入TaskPool内部任务队列等待执行
taskpool.execute(task, taskpool.Priority.HIGH).then((res: string[]) => {
// so库预加载完成的处理
logger.info(TAG, '%{public}s', 'PreloadSOByTaskPool:' + JSON.stringify(res));
})
} catch (err) {
logger.error(TAG, "PreloadSOByTaskPool: execute failed, " + (err as BusinessError).toString());
}
}
  1. 在Ability的onCreate生命周期函数中,调用preloadSOByTaskPool开启子线程,完成so库的预加载。
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 在TaskPool子线程预加载so
preloadSOByTaskPool();
}
  1. 后续可以通过句柄使用so库中的函数。
  • 在Native层引入头文件global_handlers.h。
    #include "global\_handlers.h"
  • 编写napi接口,用于实现ArkTS层和so库之间的交互
static napi_value GetTotalRawFileContent(napi_env env, napi_callback_info info){}
static napi_value GetRawFileContent(napi_env env, napi_callback_info info) {}
  • 在napi接口中从全局对象global_handlers中取出对应so库的句柄。
// 从全局对象中获取指定so库的句柄
void *handler = global_handlers["libnativerawfile.so"];
  • 句柄不为空时,使用dlsym查找和调用so库中的符号。
// TODO:知识点:使用dlsym查找和调用so库中的符号
GetTotalRawFileContentWrapperFunc getTotalRawFileContentWrapper =
reinterpret_cast<GetTotalRawFileContentWrapperFunc>(dlsym(handler, "GetTotalRawFileContentWrapper"));
if (getTotalRawFileContentWrapper) {
// 调用 GetRawFileContentWrapper 函数
napi_value result = getTotalRawFileContentWrapper(env, info);
OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, " GetRawFileContentWrapper finish");
return result;
} else {
// 处理无法获取函数指针的情况
OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, " GetTotalRawFileContentWrapper fn failed");
return nullptr;
}
  • 在ArkTS层调用编写的napi接口,就可以使用so库导出的函数
this.rawfileContent = nativeRawfileApi.getRawFileContent(getContext().resourceManager, 'rawfile.txt', 2, 5);

Native中加入hilog日志的实现主要步骤如下

  1. 在CMakeLists中通过target_link_libraries导入日志模块libhilog_ndk.z.so。
target_link_libraries(nativerawfile PUBLIC libace_napi.z.so libhilog_ndk.z.so librawfile.z.so)
  1. 在需要打印hilog日志的cpp文件开头引入头文件 #include "hilog/log.h"。
#include "hilog/log.h"
  1. 在需要打印日志的地方通过OH_LOG_Print打印日志。日志级别有LOG_INFO、LOG_ERROR等
OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetRawFileContent Begin");

Native读取Rawfile中文本文件部分内容主要步骤如下:

  1. 在前端通过调用Native中的getRawFileContent接口读取文件部分内容。传入的参数为文件名、开始读取位置、读取文件长度。
Button($r('app.string.ReadButton'))
.onClick(()=> {
this.rawfileContent = nativeRawfileApi.getRawFileContent(getContext().resourceManager, 'rawfile.txt', this.ReadStartPos, this.readLength);
}).margin($r('app.string.rawfile_margin'))
  1. 在Native侧native_rawfile.cpp的getRawFileContent接口中通过Rawfile的API接口以及pread函数读取Rawfile文件部分内容。
 // TODO 知识点:通过pread读取文件部分内容。
if ((ret = pread(descriptor.fd, buf, lenContent, descriptor.start + startPos)) == -1) {
OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "GetRawFileContent pread error!");
} else {
buf[lenContent] = '\0';
OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetRawFileContent: %{public}ld: %{public}ld: %{public}s\n",
descriptor.start, len, buf);
}

高性能知识点

不涉及

工程结构&模块类型

nativerawfile                               // har类型
|---libs\
| |---arm64-v8a\libnativeRawFile.so // arm64-v8a类型so库
| |---armeabi-v7a\libnativeRawFile.so // armeabi-v7a类型so库
| |---x86_64\libnativeRawFile.so // x86_64类型so库
|---src\main\ets\components\mainpage\
| |---MainPage.ets // 视图层-Rawfile场景主页面
|---src\main\ets\utils\
| |---Constants.ets // 常量数据
| |---TaskPool.ets // TaskPool子线程加载so库
|---src\main\cpp\
| |---include\global_handlers.h // native层-全局句柄头文件
| |---global_handlers.cpp // native层-定义全局句柄对象
| |---preloadso.cpp // native层-加载libnativeRawFile.so业务逻辑
| |---nativeRawFile.cpp // native层-读取Rawfile文件部分内容业务逻辑,libnativeRawFile.so源代码
| |---native_rawfile_api.cpp // native层-libnativeRawFile.so和ArkTS中间层接口

模块依赖

  1. 本实例依赖common模块来实现公共组件FunctionDescription。

参考资料

公共组件FunctionDescription

HarmonyOS NEXT应用开发之预加载so并读取RawFile文件的更多相关文章

  1. 通过link的preload进行内容预加载

    Preload 作为一个新的web标准,旨在提高性能和为web开发人员提供更细粒度的加载控制.Preload使开发者能够自定义资源的加载逻辑,且无需忍受基于脚本的资源加载器带来的性能损失. <l ...

  2. AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)

    AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记) 前言 在"AngularJS项目开发技巧之图片预加载" ...

  3. AngularJS进阶(三十)AngularJS项目开发技巧之图片预加载

    AngularJS项目开发技巧之图片预加载 绪 项目(移动端采用Ionic 框架)开发完毕,测试阶段发现移动APP首页的广告图片(图片由服务器端返回相应url地址)很难加载,主要原因还是网速.如下图左 ...

  4. Android--------WebView+H5开发仿美团 预加载,加载失败和重新加载

    Android嵌入式开发已经占大多数了,很多界面都是以网页的形式展示,WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. 本博客主要是模仿美团的旅游出行模块的预加载,网页加载失 ...

  5. HBuilder mui 手机app开发 Android手机app开发 ios手机app开发 打开新页面 预加载页面 关闭页面

    创建子页面 在mobile app开发过程中,经常遇到卡头卡尾的页面,此时若使用局部滚动,在android手机上会出现滚动不流畅的问题: mui的解决思路是:将需要滚动的区域通过单独的webview实 ...

  6. 利用简洁的图片预加载组件提升h5移动页面的用户体验

    在做h5移动页面,相信大家一定碰到过页面已经打开,但是里面的图片还未加载出来的情况,这种问题虽然不影响页面的功能,但是不利于用户体验.抛开网速的原因,解决这个问题有多方面的思路:最基本的,要从http ...

  7. ASP.NET MVC3 Razor 调试与预加载

    目录(?)[-] 获取服务器信息 FormsAuthenticationSlidingExpiration 属性 MVC3预加载   在ASP.NET MVC3开发中,调试中怎么也是不可缺少的,那对于 ...

  8. JS实现图片预加载无需等待

    网站开发时经常需要在某个页面需要实现对大量图片的浏览;用javascript来实现一个图片浏览器,让用户无需等待过长的时间就能看到其他图片 网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考 ...

  9. 使用 SVG 实现一个漂亮的页面预加载效果

    今天我们要为您展示如何使用 CSS 动画, SVG 和 JavaScript 创建一个简单的页面预加载效果.对于网站来说,这些预载入得画面提供了一种创造性的方法,使用户在等待内容加载的时候不会那么无聊 ...

  10. 详解HTML5中rel属性的prefetch预加载功能使用

    在HTML5中,有个很有用但常被忽略的特性,就是预先加载(prefetch),它的原理是: 利用浏览器的空闲时间去先下载用户指定需要的内容,然后缓存起来,这样用户下次加载时,就直接从缓存中取出来,效率 ...

随机推荐

  1. NJUPT自控第一次积分赛的小总结(二)基于simpleFOC的无刷电机控制

    新人一枚,写的比较水,欢迎大佬指正! 先说一下我用的物料与开发环境吧: 无刷电机:makerbase的2804电机(带AS5600磁编码器) 电机驱动板:simpleFOCmini(学校推荐的) 电池 ...

  2. 配置Tomcat服务器

    一:修改服务器端口 访问tomcat主页的时候,输入的是localhost:8080,说明tomcat的端口是8080,那么怎么修改端口号呢? 我们要先认识配置文件 用浏览器打开tomcat下conf ...

  3. 笔记:vite 的启动链路以及背后的部分原理

    这里分享一篇找到的文章 原文地址:https://blog.csdn.net/frontend_frank/article/details/106632197 NO.1 vite 是什么 vite - ...

  4. 用免费GPU部署自己的stable-diffusion项目(AI生成图片)

    2021年时出现了 openAI 的 DALL,但是不开源.2022年一开年,DALL-E 2发布,依然不开源.同年7月,Google 公布其 Text-to-Image 模型 Imagen,并且几乎 ...

  5. LOTO示波器选型指南

    LOTO示波器选型指南 LOTO示波器属于虚拟示波器,产品主要基于USB接口的,所以使用LOTO示波器产品需要配备一台Windows电脑或者Android(安卓)智能手机/平板. 针对一些特殊应用的工 ...

  6. Nancy一个轻量级用于构建基于 HTTP 的 Web 服务

    记录一下: Nancy官网地址:http://nancyfx.org/ GitHub文档地址:https://github.com/NancyFx/Nancy/wiki/Documentation 有 ...

  7. 改Bug的经验

    如果修复某个Bug花了很长时间,这时候就要问问自己为什么,怎么做才吸取经验教训,在类似的问题上不再出问题,以及采用的方法,使用的工具是否还有改进的地方: 当所有问题都解决之后,一定要梳理下从最初找Bu ...

  8. 跳转到制定Sheet页及提交指定sheet页内容

    一.跳转到指定Sheet的实现 话不多说,先上效果图 两个按钮的事件分别如下: _g().loadSheetByName("sheet1") # 跳转至sheet1按钮事件 _g( ...

  9. #floyd,分治#D 路径之和

    题目 对于每个\(y\),求除了\(y\)之外,其余的所有点组成的有序点对\((x,z)\) 不经过\(y\)的最短路长度之和(不存在即为-1).\(n\leq 320\) 分析 太妙了,首先用flo ...

  10. AJAX 前端开发利器:实现网页动态更新的核心技术

    AJAX AJAX是开发者的梦想,因为你可以: 在不重新加载页面的情况下更新网页 在页面加载后请求来自服务器的数据 在页面加载后接收来自服务器的数据 在后台向服务器发送数据 HTML页面 <!D ...