【Android NDK 开发】JNI 方法解析 ( int 数组传递 | jintArray 类型 | 数组转换 | 获取数组长度 | 获取数组元素 | 指针遍历数组 | 数组返回值设置 )(一)

简介: 【Android NDK 开发】JNI 方法解析 ( int 数组传递 | jintArray 类型 | 数组转换 | 获取数组长度 | 获取数组元素 | 指针遍历数组 | 数组返回值设置 )(一)

I . jintArray 类型说明


1 . C ++ 环境类型定义 : 下面是 jintArray 类型的定义 , jintArray 的本质是一个 _jobject 类对象指针 ;


class _jobject {};      // 定义 _jobject 类 , 这是一个空类
class _jarray : public _jobject {};     // 定义 _jarray 类 继承 _jobject 类
class _jintArray : public _jarray {}; // 定义 _jintArray 类 , 继承 _jarray 类
typedef _jintArray*     jintArray;  // 定义 _jintArray* 别名 , jintArray



public 继承 : 父类成员在子类中访问级别不变



2 . jintArray 类型本质 : jintArray 是一个 _jintArray 类的指针 , 其 _jintArray 类 对象存储在内存中 , _jintArray * 指针指向该内存 ;


为 _jintArray * 指针变量类型 定义别名 jintArray 类型 ;



3 . ( jintArray -> jint * ) 类型转换 : 这是 Java 中的 int 数组的内存地址 , 如果要在 C/C++ 环境中使用 , 要将该 jintArray 类型变量转为 jint* 类型的变量 ;


使用 jint* GetIntArrayElements(jintArray array, jboolean* isCopy) 方法 , 可以实现上述转化 ( jintArray -> jint * ) ;




II . jboolean 类型说明


1 . C ++ 环境类型定义 : 下面是 jboolean 类型的定义 , jboolean 本质是 无符号 char 类型 ;


typedef unsigned char __uint8_t;  // 定义 char 类型别名 __uint8_t
typedef __uint8_t uint8_t;  // 定义 __uint8_t 类型别名 uint8_t
typedef uint8_t  jboolean;    // 定义 uint8_t 类型别名 jboolean


2 . jboolean 类型取值 : jboolean 的取值只能是 0 和 1 , 也可以使用 JNI_FALSE 和 JNI_TRUE 宏定义 ;


#define JNI_FALSE 0
#define JNI_TRUE 1



III . GetIntArrayElements 方法解析 ( jintArray -> jint* | int* )


1 . GetIntArrayElements 函数作用 : 将 Java 环境的 int 数组类型变量 ( jintArray 类型 ) , 转为 C/C++ 环境中的 jint 数组指针 , 返回一个指针指向 jint 数组首元素地址 ;


jint 本质就是 int 类型 , GetIntArrayElements 函数作用就是将 jintArray 转为 int* 指针 ;



2 . GetIntArrayElements 函数原型 :


struct _JNIEnv {
    /* _JNIEnv  结构体中封装了 JNINativeInterface 结构体指针 */
    const struct JNINativeInterface* functions;
    ...
    jint* GetIntArrayElements(jintArray array, jboolean* isCopy)
    { 
      // 调用 JNINativeInterface 结构体中封装的 GetIntArrayElements 方法
      return functions->GetIntArrayElements(this, array, isCopy); 
    }
    ...
}


3 . jintArray array 参数 : 该参数是从 Java 层调用传入的参数 , jintArray 的本质是一个 _jobject 类对象指针 ;



4 . jboolean* isCopy 参数 : 该参数用于指定将 jintArray 类型的变量 , 转为 jint * 指针类型的变量 , 新的指针变量的生成方式 ;



① 将 该参数设置成指向 JNI_TRUE 的指针 : 将 int 数组数据拷贝到一个新的内存空间中 , 并将该内存空间首地址返回 ;


② 将 该参数设置成指向 JNI_FALSE 的指针 : 直接使用 java 中的 int 数组地址 , 返回 java 中的 int 数组的首地址 ;


③ 将 该参数设置成 NULL ( 推荐 ) : 表示不关心如何实现 , 让系统自动选择指针生成方式 , 一般情况下都不关心该生成方式 ;



5 . 代码示例 :



① jboolean* isCopy 参数 准备 代码示例 : jboolean 类型变量可取值 JNI_FALSE 0 和 JNI_TRUE 1 两个值 ;


 

jboolean isCopy = JNI_TRUE;

② GetIntArrayElements 方法调用代码示例 :


intArray_ 是 Java 层传入的 jintArray intArray_ 参数变量 ;

JNIEnv *env 是 JNI 方法的默认参数 , 这里是 C++ 环境中的 JNIEnv 指针类型 ;

jboolean* isCopy 设置成 NULL 参数表示 不关心 jint* 类型变量的生成方式 ;


jint *intArray = env->GetIntArrayElements(intArray_, NULL);


如果是其它基础数据类型的数组 , 将 Get***ArrayElements 方法名中的 基础数据类型修改一下即可 ;


如果是布尔类型的数组 , 使用 GetBooleanArrayElements 方法 ;

如果是浮点型的数组 , 使用 GetFloatArrayElements 方法 ;

如果是字符型的数组 , 使用 GetCharArrayElements 方法 ;



IV . jarray 类型说明


1 . jarray 类型 : 该类型的本质是一个指针 , 指向一个空对象地址 , 这个对象一般是从 Java 层传递进来 ;


class _jobject {};      // 定义 _jobject 空类
class _jarray : public _jobject {};  // 定义 _jarray 类 , 继承 _jobject 类
typedef _jarray*        jarray;   // 定义 _jarray* 指针类型 别名为 jarray



2 . _jarray 类子类 : 下面定义的 9 个类 , 都是 _jarray 子类 , 都可以使用 GetArrayLength 方法获取数组长度 ;


class _jarray : public _jobject {};
//下面定义的都是 jarray 子类
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};



3 . Java 传入的数组类型别名 : 下面定义的 9 个别名 , 本质上都是 _jarray 类型对象 或者 其子类对象的 指针 , 即 _jarray* 类型 ;


typedef _jarray*        jarray;
//下面是 9 个是 Java 传入的数组类型别名
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;



V . GetArrayLength 方法解析 ( 获取 jarray 数组长度 )


1 . 函数作用 : 获取 jarray 数组长度 , 该 jarray 类型可以是下面定义的类型 ;


typedef _jarray*        jarray;
//下面是 9 个是 Java 传入的数组类型别名
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;



2 . 函数原型 :


struct _JNIEnv {
    /* _JNIEnv  结构体中封装了 JNINativeInterface 结构体指针 */
    const struct JNINativeInterface* functions;
    ...
    jsize GetArrayLength(jarray array)
    { 
      调用 JNINativeInterface 结构体中封装的 GetArrayLength 方法
      return functions->GetArrayLength(this, array); 
    }
    ...
}


3 . 返回值类型说明 : jsize 类型本质还是 int 类型 ;


typedef int __int32_t;
typedef __int32_t     int32_t;
typedef int32_t  jint;
typedef jint     jsize;



4 . 函数调用示例 : 其中的 jintArray intArray_ 是 Java 层传入的参数 ;


jsize len = env->GetArrayLength(intArray_);




VI . 日志打印


1 . 日志库配置 :



① 导入日志库 : #include <android/log.h>


② CMake 设置日志库 : add_library 设置动态库名称 , find_library 中为 查找日志库 ,

target_link_libraries 连接日志库 ;
add_library( 
        native-lib
        SHARED
        native-lib.cpp)
find_library( 
        log-lib
        log)
target_link_libraries( 
        native-lib
        ${log-lib})



2 . 日志打印函数函数原型 :


int __android_log_print(int prio, const char* tag, const char* fmt, ...)



3 . 日志打印函数参数说明 :



① int prio 参数 : 日志的等级 , 定义在 log.h 的 android_LogPriority 枚举中 ;

ANDROID_LOG_VERBOSE
ANDROID_LOG_DEBUG
ANDROID_LOG_INFO
ANDROID_LOG_WARN
ANDROID_LOG_ERROR


② const char* tag 参数 : 日志打印的 TAG 标签 , 这是一个 C/C++ char* 类型字符串 ;

③ const char* fmt, … 参数 : 可变参数 ;


4 . 日志打印函数代码示例 :


   

/*
            __android_log_print 打印 Android 日志函数
                函数原型 : int __android_log_print(int prio, const char* tag, const char* fmt, ...)
                int prio 参数 : 日志的等级 , 定义在 jni.h 的 android_LogPriority 枚举中
                                ANDROID_LOG_VERBOSE
                                ANDROID_LOG_DEBUG
                                ANDROID_LOG_INFO
                                ANDROID_LOG_WARN
                                ANDROID_LOG_ERROR
                const char* tag 参数 : 日志打印的 TAG 标签 , 这是一个 C/C++ char* 类型字符串
                const char* fmt, ... 参数 : 可变参数
         */
        __android_log_print(ANDROID_LOG_INFO, "JNI_TAG" , "%d . %d" , i , *num);




VII . 遍历 int 数组


1 . 使用指针遍历 jint 数组 : jint *intArray ;



intArray 是数组首元素地址

intArray + 1 是第 1 个元素的首地址

intArray + k 是第 k 个元素的首地址



2 . 函数调用 代码示例 :


 

/*
        使用指针进行访问
        intArray 是数组首元素地址
        intArray + 1 是第 1 个元素的首地址
        intArray + k 是第 k 个元素的首地址
        使用 *(intArray + k) 可以获取第 k 个元素的值
     */
    for(int i = 0; i < len; i ++){
        //获取第 i 个元素的首地址 , 使用 *num 可以获取第 i 个元素的值
        int *num = intArray + i;
        /*
            __android_log_print 打印 Android 日志函数
                函数原型 : int __android_log_print(int prio, const char* tag, const char* fmt, ...)
                int prio 参数 : 日志的等级 , 定义在 jni.h 的 android_LogPriority 枚举中
                                ANDROID_LOG_VERBOSE
                                ANDROID_LOG_DEBUG
                                ANDROID_LOG_INFO
                                ANDROID_LOG_WARN
                                ANDROID_LOG_ERROR
                const char* tag 参数 : 日志打印的 TAG 标签 , 这是一个 C/C++ char* 类型字符串
                const char* fmt, ... 参数 : 可变参数
         */
        __android_log_print(ANDROID_LOG_INFO, "JNI_TAG" , "%d . %d" , i , *num);
        //修改数组中的值
        *num = 8888;
    }



目录
相关文章
|
4月前
|
数据采集 监控 API
告别手动埋点!Android 无侵入式数据采集方案深度解析
传统的Android应用监控方案需要开发者在代码中手动添加埋点,不仅侵入性强、工作量大,还难以维护。本文深入探讨了基于字节码插桩技术的无侵入式数据采集方案,通过Gradle插件 + AGP API + ASM的技术组合,实现对应用性能、用户行为、网络请求等全方位监控,真正做到零侵入、易集成、高稳定。
662 59
|
4月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
293 3
|
8月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
386 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
11月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
440 15
|
11月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
数据采集 分布式计算 数据处理
Dataphin常见问题之与指定类型int不兼容如何解决
Dataphin是阿里云提供的一站式数据处理服务,旨在帮助企业构建一体化的智能数据处理平台。Dataphin整合了数据建模、数据处理、数据开发、数据服务等多个功能,支持企业更高效地进行数据治理和分析。
|
SQL 流计算 OceanBase
OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
【2月更文挑战第25天】OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
422 3
|
11月前
|
Python Windows
[oeasy]python076_int这个词怎么来的_[词根溯源]整数类型_int_integer_touch
本文探讨了“int”一词的起源及其与整数类型的关联。通过词根溯源,揭示“int”来源于“integer”,意为“完整的数”,与零碎的分数相对。同时分析了相关词汇如“tact”(接触)、“touch”(触摸)及衍生词,如“tangential”(切线的)、“intagible”(无形的)和“integral”(完整的、不可或缺的)。文章还结合编程语言特性,解释了Python作为动态类型、强类型语言的特点,并总结了整型变量的概念与意义。最后预告了后续内容,提供了学习资源链接。
414 11
|
11月前
|
存储 C语言 Python
[oeasy]python077_int类型怎么用_整数运算_integer_进制转化_int类
本文主要讲解了Python中`int`类型的应用与特性。首先回顾了`int`词根的溯源,探讨了整型变量的概念及命名规则(如匈牙利命名法)。接着分析了整型变量在内存中的存储位置和地址,并通过`type()`和`id()`函数验证其类型和地址。还介绍了整型变量的运算功能,以及如何通过`int()`函数将字符串转化为整数,支持不同进制间的转换(如二进制转十进制)。此外,文章提及了关键字`del`的使用场景,对比了Python与C语言中`int`的区别,并总结了整型与字符串类型的差异,为后续深入学习奠定基础。
273 1

热门文章

最新文章

推荐镜像

更多