Java -- 常用的JNI接口函数简介(二)_newobjectarray_第一序列丶的博客-程序员秘密

技术标签: framework  JNI  c语言  native  编程开发杂类  Android  

Java -- 常用的JNI接口函数简介(二)

 

接着上一篇,再继续介绍一些其他常用的JNI接口函数(函数调用示例基于C++实现)。

 

一、数组操作

 

1、获取数据长度

在JNI中,如果我们需要获取常如数组参数的长度值,可以调用jsize GetArrayLength(JNIEnv *env, jarray array):

GetArrayLength
 
jsize GetArrayLength(JNIEnv *env, jarray array);
 
Returns the number of elements in the array.

PARAMETERS:
 
env: the JNI interface pointer.
 
array: a Java array object.
 
RETURNS:
 
Returns the length of the array.

返回值为数组的长度,示例:

static void android_animation_PropertyValuesHolder_callMultipleFloatMethod(
        JNIEnv* env, jclass pvhObject, jobject target, jlong methodID, jfloatArray arg)
{
    jsize parameterCount = env->GetArrayLength(arg);
    ...
}

2、创建数组

创建数组,需要调用NewObjectArray():

NewObjectArray
 
jobjectArray NewObjectArray(JNIEnv *env, jsize length,
 jclass elementClass, jobject initialElement);
 
Constructs a new array holding objects in class elementClass. All elements are initially set to initialElement.

PARAMETERS:
 
env: the JNI interface pointer.
 
length: array size.//需创建的数组大小
 
elementClass: array element class. //数组元素类型
 
initialElement: initialization value.//初始值,一般为NULL
 
RETURNS:
 
Returns a Java array object, or NULL if the array cannot be constructed.

例如,我们可以在JNI中创建一个数组,作为参数去调用Java层的某个方法。创建一个长度为array_size、元素类型为String的数组:

    jclass string_class = env->FindClass("java/lang/String");
    jobjectArray string_array = env->NewObjectArray(array_size, string_class, NULL);

3、获取/设置数组元素

操作数组元素是我们经常要使用的,JNI提供了两个函数让开发者操作数组:

GetObjectArrayElement
 
jobject GetObjectArrayElement(JNIEnv *env,
 jobjectArray array, jsize index);
 
Returns an element of an Object array.

PARAMETERS:
 
env: the JNI interface pointer.
 
array: a Java array.
 
index: array index.
 
RETURNS:
 
Returns a Java object.
 
THROWS:
 
ArrayIndexOutOfBoundsException: if index does not specify a valid index in the array.
SetObjectArrayElement
 
void SetObjectArrayElement(JNIEnv *env, jobjectArray array,
 jsize index, jobject value);
 
Sets an element of an Object array.

PARAMETERS:
 
env: the JNI interface pointer.
 
array: a Java array.
 
index: array index.
 
value: the new value.

GetObjectArrayElement()函数获取某个数组中、某个下标值的元素值;SetObjectArrayElement()设置某个数组、某个下标的元素值。

 

二、注册JNI函数

 

在Android中,我们实现了JNI函数之后,必须要对其进行注册,我们才能正常使用。JNI中注册native方法,需调用:

RegisterNatives
 
jint RegisterNatives(JNIEnv *env, jclass clazz,
 const JNINativeMethod *methods, jint nMethods);
 
Registers native methods with the class specified by the clazz argument. 
The methods parameter specifies an array of JNINativeMethod structures that contain the names, signatures
, and function pointers of the native methods. 
The name and signature fields of the JNINativeMethod structure are pointers to modified UTF-8 strings. 
The nMethods parameter specifies the number of native methods in the array. 
The JNINativeMethod structure is defined as follows:

typedef struct { 

    char *name; //Java中定义的方法名

    char *signature; //Java中方法的函数签名

    void *fnPtr; //函数指针,指向native函数;与参数name一一对应

} JNINativeMethod; 

 
The function pointers nominally must have the following signature:

ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass, ...); 

PARAMETERS:
 
env: the JNI interface pointer.
 
clazz: a Java class object.//与该JNI文件相关联的Java类全限定名
 
methods: the native methods in the class.//需要注册的JNI方法数组
 
nMethods: the number of native methods in the class.//需注册的JNI方法的个数
 
RETURNS:
 
Returns “0” on success; returns a negative value on failure.

在调用该方法时,methods参数一般传递的是JNINativeMethod类型的数组,它包含了所有需要需要注册的JNI方法。
示例:需要注册的JNI方法:

JNINativeMethod gMethods[] = {
    {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;ILjava/lang/String;)J", (void *)add},
    {"nativeRemove", "(J)V", (void *)remove},
    {"nativeSetMode", "(I)V", (void *)setMode},
    {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
};
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
jclass clazz;
    if ((clazz = env->FindClass("android/net/rtp/AudioGroup")) == NULL ||
        (gNative = env->GetFieldID(clazz, "mNative", "J")) == NULL ||
        (gMode = env->GetFieldID(clazz, "mMode", "I")) == NULL ||
        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
        ALOGE("JNI registration failed");
        return -1;
    }
    return 0;

取消注册的函数较为简单:

UnregisterNatives
 
jint UnregisterNatives(JNIEnv *env, jclass clazz);
 
Unregisters native methods of a class. 

PARAMETERS:
 
env: the JNI interface pointer.
 
clazz: a Java class object.
 
RETURNS:
 
Returns “0” on success; returns a negative value on failure.

传递需要unregister的Java类的类对象即可。

 

三、C/C++JNI接口函数的调用形式

 

需要重申,native函数的C/C++实现,JNI函数调用的方式是不同的,看官方文档中的例子:

Native Method Arguments
 
The JNI interface pointer is the first argument to native methods. 
The JNI interface pointer is of type JNIEnv. The second argument differs depending on whether the native method is static or nonstatic. 
The second argument to a nonstatic native method is a reference to the object. 
The second argument to a static native method is a reference to its Java class.

The remaining arguments correspond to regular Java method arguments. 
The native method call passes its result back to the calling routine via the return value. 
 
Code Example 2-1 illustrates using a C function to implement the native method f. 
The native method f is declared as follows:

package pkg;  

class Cls { 

     native double f(int i, String s); 

     ... 

} 
The C function with the long mangled name Java_pkg_Cls_f_ILjava_lang_String_2 implements native method f:
 
Code Example 2-1 Implementing a Native Method Using C

jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
     JNIEnv *env,        /* interface pointer */
     jobject obj,        /* "this" pointer */
     jint i,             /* argument #1 */
     jstring s)          /* argument #2 */
{
     /* Obtain a C-copy of the Java string */
     const char *str = (*env)->GetStringUTFChars(env, s, 0);

     /* process the string */
     ...

     /* Now we are done with str */
     (*env)->ReleaseStringUTFChars(env, s, str);

     return ...
}
Note that we always manipulate Java objects using the interface pointer env . 
Using C++, you can write a slightly cleaner version of the code, as shown in Code Example 2-2:
 
Code Example 2-2 Implementing a Native Method Using C++

extern "C" /* specify the C calling convention */  

jdouble Java_pkg_Cls_f__ILjava_lang_String_2 ( 

     JNIEnv *env,        /* interface pointer */ 

     jobject obj,        /* "this" pointer */ 

     jint i,             /* argument #1 */ 

     jstring s)          /* argument #2 */ 

{ 

     const char *str = env->GetStringUTFChars(s, 0); 

     ... 

     env->ReleaseStringUTFChars(s, str); 

     return ... 

} 
With C++, the extra level of indirection and the interface pointer argument disappear from the source code.
However, the underlying mechanism is exactly the same as with C. 
In C++, JNI functions are defined as inline member functions that expand to their C counterparts.

从上述的官方示例中,我们可以看出:1、相对于C语言,C++实现中调用JNI接口函数少了一次解引用和参数传递;2、不管是C,还是C++形式的JNI调用,本质都是一样的。
至于JNI是用C,还是C++,可以根据自己的需求而定。Android framework中,JNI大部分都是C++实现的。





 

 

 

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/csdn_of_coder/article/details/52203935

智能推荐

【NOI导刊】黑匣子_*noi导刊_Zhayan9QvQ的博客-程序员秘密

题目描述 Description我们使用黑匣子的一个简单模型。它能存放一个整数序列和一个特别的变量i。在初始时刻,黑匣子为空且i等于0。这个黑匣子能执行一系列的命令。有两类命令:ADD(x):把元素x放入黑匣子;GET:把i加1的同时,输出黑匣子内所有整数中第i小的数。牢记第i小的数是当黑匣子中的元素已非降序排序后位于第i位的元素。下面的表6_4是一个11个命令的例子:表6_4

leetcode-127-单词接龙-java_单词接龙,相邻两个单词只能改变一个字母_xushiyu1996818的博客-程序员秘密

题目及测试package pid127;/* 单词接龙给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: 每次转换只能改变一个字母。 转换过程中的中间单词必须是字典中的单词。说明: 如果不存在这样的转换序列,返回 0。 所有单词具有相同的长度...

移植安装ModBus到ARM开发板_muduo移植到arm_liuxd3000的博客-程序员秘密

1、libmodbus官网2、下载二、交叉编译1、解压2、创建安装目录3、进入解压的目录4、配置编译选项5、编译6、安装7、生成动态链接库三、移植到ARM开发板1、复制文件到ARM开发板四、创建测试程序1、创建测试程序C文件2、复制库中头文件3、交叉编译4、复制可执行文件到开发板五、安装ModbusPoll及ModbusSlave六、测试1、测试准备2、在ARM上运行test程序3、移植成功一、源码下载1、libmo

数据库练习题3--sql基础_下列语句执行后的输出结果是( ) declare @r int set @r=power(3,2) _ssdssa的博客-程序员秘密

一、练习目的1.理解局部变量和全局变量的概念和使用方法;2.掌握各种运算符的使用;3.掌握基本的SELECT语句的使用方法;4.掌握SQL-Server中流程控制语句的使用;5.掌握系统函数及用户自定义函数的使用。1.定义一个int的整形变量,并分别给其赋值67、123067。declare @m int=67print @mdeclare @m int=123067print @m2.定义一个长度为11的可变长形字符变量,并分别给其赋值“Hello World!”和“How are

Linux(三)远程登录管理工具_连接linux系统的远程管理工具有哪些_include_ice的博客-程序员秘密

远程登录管理工具,是为了不需要去到电脑面前操作毕竟如果有上百台服务器,怎么可能一台一台的去操作.所以有必要用一台电脑,连接上不同的服务器操作会更方便要用远程登录,自然要先设置好网络首先打开虚拟机,这是我安装好第一次启动的画面,默认启动图形化桌面先右键装好的Linux系统,选设置然后弹出虚拟机设置窗口.网络链接中有三种模式桥接,NAT,仅主机模式桥接模式:利用物理机的网卡,与本地物理机或其他物理机或...

软件项目管理案例教程第4版课后习题第一章_若逢雪初霁的博客-程序员秘密

第一章一、填空题二、判断题三、选择题四、问答题一、填空题1.敏捷模型包括(4)个核心价值,对应(12)个敏捷原则。详解: 敏捷开发4句宣言: 个体与交互 胜过 过程与工具可以工作的软件 胜过 面面俱到的文档客户协作 胜过 合同谈判响应变化 胜过 遵循计划 敏捷开发12个原则:1、最先要做的是通过尽早地、持续地交付有价值的软件来使客户满意。2、即使到了开发的后期,也欢迎改变需求。敏捷过程利用适应变化来为客户创造竞争优势。(适应需求变更)3、经常性地交付可以工作的软件,交付的间隔可以从

随便推点

mvp架构,dagger2,butterknife的使用_ocean_forest的博客-程序员秘密

mvp架构,dagger2,butterknife的使用butterKnife框架简介ButterKnife的优势ButterKnife的使用dagger2Dagger2是什么?框架说明Dagger2与butterknife区别依赖注入Dagger2注解说明Dagger2基本使用:Dagger2复杂使用:小结butterKnife框架简介注于Android系统的View注入框架,当一个布局十分...

Linux入门真经-028硬盘结构与linux设备文件_TheMonkeyKing_的博客-程序员秘密

本节为大家介绍硬盘的种类、结构,以及分区相关的基础知识。我们都知道,硬盘是用于存取数据的。现在常见的硬盘类型有机械硬盘和固态硬盘。而机械硬盘和固态硬盘的结构又有着很大的区别。接下来分别向大家介绍机械硬盘和固态硬盘,然后介绍一些分区必要的基础知识。 1、机械硬盘对于机械硬盘来说,数据存储在磁盘上的磁性介质之中,计算机想要从硬盘中读取数据时,需要遵循相关的硬盘接口协议(如SCSI、...

中职计算机基础人才培养方案,中职计算机基础WORD 教案及中职机电技术应用(智能制造方向)人才培养方案.doc..._欣睿(兰静)的博客-程序员秘密

课程名称计算机基础上课时间第 周周 第 节课 题第4章 文字处理软件的应用4.4 制作电子小报教学目标知识与技能方面:1 会使用Word 中的图片编辑功能2 熟悉图文混排、页面设置和文本框及艺术字使用情感方面: 培养学生的设计能力和创新意识教学类型新授课教学方法讲授课 时一课时教学重点图文混排、页面设置和文本框及艺术字使用教学难点图文混排教学过程导入新课:教师提出具体的工...

《剑指Offer——名企面试官精讲典型编程题(纪念版)》已经出版_剑指offer第二版_cadcisdhht的博客-程序员秘密

《剑指Offer:名企面试官精讲典型编程面试题》一书从2011年年底出版以来,已经两年多过去了。在这段时间里,我自己的生活和工作都发生了很大的变化。写书的时候儿子小呼呼还没有出生,我还只能透过他妈妈的肚皮感受他的胎动。这次在为纪念版添加新内容的时候,他会时不时跑过来要求坐到我的膝盖上,然后在笔记本的触摸屏上指指点点。当时我还在思科工作,现在已经重新回到了微软。工作之余,我在《剑指Offer》这

list.stream() 获取实体中某个字段列_list stream 取字段_侯志杰的博客-程序员秘密

比如我要取 实体列表中的id字段;方法有很多,比如for循环,但是代码量比较多;简单的方法就是利用 stream()流处理;栗子:List&lt;Entity&gt; list= 你的接口;List&lt;Long&gt; collect =list.stream ().map(Entity::getId).collect (Collectors.toList ());这样,你就得到了id串了。...

常用反跟踪技术_pll621的博客-程序员秘密

作者:smokingroom日期:2005-04-12站点:www.programmerlife.com邮箱:[email protected]前言:反跟踪调试技术对于Delphi程序员来说,似乎比较陌生。因为许多的技术,直接用Delphi语言似乎比较难以完成,而对汇编来说,则比较容易完成,因此,下面的代码用到了内嵌汇编语言。如果你看不懂也不要紧,因为已经经过测试,可以直接放进你的程序里面。