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

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
日志服务 SLS,月写入数据量 50GB 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;
    }



目录
打赏
0
0
0
0
39
分享
相关文章
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
23 7
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
121 1
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
4月前
|
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
106 0
安卓与iOS的较量:技术深度解析
【10月更文挑战第24天】 在移动操作系统领域,安卓和iOS无疑是两大巨头。本文将深入探讨这两个系统的技术特点、优势和不足,以及它们在未来可能的发展方向。我们将通过对比分析,帮助读者更好地理解这两个系统的本质和内涵,从而引发对移动操作系统未来发展的深思。
94 0
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
142 2
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
    13
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    17
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    9
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    3
  • 5
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    9
  • 6
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    1
  • 7
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    10
  • 8
    Android实战经验之Kotlin中快速实现MVI架构
    11
  • 9
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    4
  • 10
    android FragmentManager 删除所有Fragment 重建
    3
  • 推荐镜像

    更多
    AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等