介绍

本示例主要介绍在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. 【大语言模型基础】GPT(Generative Pre-training )生成式无监督预训练模型原理

    GPT,GPT-2,GPT-3 论文精读[论文精读]_哔哩哔哩_bilibili   ELMo:将上下文当作特征,但是无监督的语料和我们真实的语料还是有区别的,不一定符合我们特定的任务,是一种双向的特 ...

  2. day13-Servlet03

    Servlet03 11.练习 快捷键-可以快速地在访问的文件件切换 ctrl+alt+向左箭头:回到上次访问的位置 ctrl+alt+向右箭头:回到下一步访问的位置 11.1CatServlet 首 ...

  3. 【atcoder abc276 】(a* 搜索)

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  4. RecyclerView问题汇总

    目录介绍 25.0.0.0 请说一下RecyclerView?adapter的作用是什么,几个方法是做什么用的?如何理解adapter订阅者模式? 25.0.0.1 ViewHolder的作用是什么? ...

  5. App启动页面优化

    目录介绍 01.存在白屏问题 1.1 问题描述 1.2 问题分析 02.解决白屏的办法 2.1 解决方案分析 2.2 第一种解决方案 2.3 第二种解决方案 2.4 注意要点 03.Applicati ...

  6. 【LeetCode刷题】744. 寻找比目标字母大的最小字母

    744. 寻找比目标字母大的最小字母(点击跳转LeetCode) 给你一个排序后的字符列表 letters ,列表中只包含小写英文字母.另给出一个目标字母 target,请你寻找在这一有序列表里比目标 ...

  7. Python 合并Excel文件(Excel文件多sheet)

    一.Python合并Excel文件多sheet<方法1> import os import pandas as pd # 指定包含Excel文件的文件夹路径 folder_path = ' ...

  8. flutter3-dylive仿抖音App实例|Flutter3+Getx实战短视频直播应用

    原创研发flutter3+getX+mediaKit跨平台仿抖音app短视频直播实战Flutter3-DouYin. flutter3_dylive使用最新跨平台技术flutter3.x+dart3+ ...

  9. Bad magic number for central directory

    Bad magic number for central directory 运行代码输出如下bug: File "/home/a/Prediction/Predict_Models.py& ...

  10. kingbaseES V8R6 备份恢复案例 -- sys_rman备份“DSO support..."故障

    案例说明: 在通过sys_rman执行备份时,出现"DSO support...."错误,如下图所示: sys_log日志: 适用版本: KingbaseES V8R6 一.问题分 ...