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

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++实现的。





 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,当Fragment需要调用JNI接口函数时,可以通过以下步骤实现: 1. 首先,在Java中创建一个JNI接口类并使用static类型,以便在不同的Fragment中简便地调用JNI函数。 2. 在JNI接口类中,定义所需的JNI函数,并使用native关键字标记这些函数,表示它们将在C / C++中实现。 3. 在C / C++中,实现JNI函数的功能。可以使用CMakeLists文件来配置和构建通过JNI调用的C / C++代码。 4. 在Java中,通过调用JNI接口类的静态方法来调用JNI函数。根据具体的需求,可以传递参数给JNI函数,并将其结果返回到Java中。 5. 在Fragment中,根据需要处理JNI函数的返回结果,并进行相应的操作。例如,可以将返回的byte数组转换为String类型,并在界面上显示相应的数据。 通过以上步骤,Android Fragment可以成功调用JNI接口函数,并实现与C / C++代码的交互。这样可以在APP开发中使用JNI调用C / C的基本架构,并为开发者提供有益的参考借鉴。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [《“透视”个人大数据》项目开发小记 --(三)Android APP 开发(3)使用jni调用c++/c 应用实例浅析](https://blog.csdn.net/m0_69502339/article/details/127995223)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [自己平时做的android相关的总结](https://download.csdn.net/download/mars_cheng/8724303)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值