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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 【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;
    }



目录
相关文章
|
25天前
|
开发框架 供应链 监控
并行开发模型详解:类型、步骤及其应用解析
在现代研发环境中,企业需要在有限时间内推出高质量的产品,以满足客户不断变化的需求。传统的线性开发模式往往拖慢进度,导致资源浪费和延迟交付。并行开发模型通过允许多个开发阶段同时进行,极大提高了产品开发的效率和响应能力。本文将深入解析并行开发模型,涵盖其类型、步骤及如何通过辅助工具优化团队协作和管理工作流。
54 3
|
14天前
|
监控 安全 Serverless
"揭秘D2终端大会热点技术:Serverless架构最佳实践全解析,让你的开发效率翻倍,迈向技术新高峰!"
【10月更文挑战第23天】D2终端大会汇聚了众多前沿技术,其中Serverless架构备受瞩目。它让开发者无需关注服务器管理,专注于业务逻辑,提高开发效率。本文介绍了选择合适平台、设计合理函数架构、优化性能及安全监控的最佳实践,助力开发者充分挖掘Serverless潜力,推动技术发展。
35 1
|
22天前
|
机器学习/深度学习 安全 搜索推荐
中国CRM市场深度解析:本土化定制开发的领军厂商与未来趋势
国内CRM软件企业正面临日益增长的本土定制需求,这不仅考验服务商的综合水平,也推动了市场的快速发展。本文将深入解析中国CRM市场的现状,探讨领军厂商的优势,并预测未来趋势,包括智能化、集成化、本土化与国际化并行及云服务模式的普及。
|
4天前
|
开发工具 Android开发 数据安全/隐私保护
探索移动应用的世界:从开发到操作系统的全面解析
【10月更文挑战第33天】在数字化时代,移动应用已成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用的开发过程,包括编程语言、开发工具和框架的选择,以及如何构建用户友好的界面。同时,我们还将分析移动操作系统的核心功能和安全性,以帮助读者更好地理解这些应用程序是如何在各种设备上运行的。无论你是开发者还是普通用户,这篇文章都将为你揭示移动应用背后的奥秘。
|
11天前
|
机器学习/深度学习 Android开发 UED
移动应用与系统:从开发到优化的全面解析
【10月更文挑战第25天】 在数字化时代,移动应用已成为我们生活的重要组成部分。本文将深入探讨移动应用的开发过程、移动操作系统的角色,以及如何对移动应用进行优化以提高用户体验和性能。我们将通过分析具体案例,揭示移动应用成功的关键因素,并提供实用的开发和优化策略。
|
30天前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
66 0
|
30天前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
51 0
|
30天前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
58 0
|
30天前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
74 0
|
10天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
29 3

推荐镜像

更多
下一篇
无影云桌面