Native是java本地方法的声明关键字,当在方法中调用一些不是由java语言写的代码或要直接操作计算机硬件或要提交某些代码的运行效率时要声明native方法.
Jni是java native interface的缩写,从字面上来说就是java本地方法的接口,所以他就是提供java native方法的声明和对上层的接口调用.
1.Jni 编写
使用native 声明_camera_open 为本地方法,并load与之相对应的动态链接库.
<span style="font-family:Microsoft YaHei;font-size:18px;"><span style="white-space: pre;"> </span>private native int _camera_open(int cameraId);</span><pre name="code" class="java"><span style="font-family:Microsoft YaHei;font-size:18px;"> private final static String studioLib = "studionative";
public static boolean loadLibrarys() {
Log.i(TAG, "loadLibrarys");
boolean status = false;
try{
System.loadLibrary(studioLib);
status = true;
}catch(Exception e){
Log.e(TAG, "exception:" + e.toString());
}
return status;
}</span>2.使用javah -jni 命令 进入bin目录下 javah -jni cn.jesse.studo.jni.StudioJni 生成一个cn_jesse_studio_jni_StudioJni.h文件,提供给native 使用.这里不了解为什么在生成的头文件中的方法会被自动加个1.
<span style="font-family:Microsoft YaHei;">/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <stdio.h>
#include <android_runtime/AndroidRuntime.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "logger.h"
/* Header for class cn_jesse_studio_jni_StudioJni */
#ifndef _Included_cn_jesse_studio_jni_StudioJni
#define _Included_cn_jesse_studio_jni_StudioJni
#ifdef __cplusplus
int register_cn_jesse_studio_jni_studioJni(JNIEnv*);
extern "C" {
#endif
/*
* Class: cn_jesse_studio_jni_StudioJni
* Method: _camera_open
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_cn_jesse_studio_jni_StudioJni__1camera_1open
(JNIEnv *, jobject, jint);
/*
* Class: cn_jesse_studio_jni_StudioJni
* Method: _serial_port_open
* Signature: (Ljava/lang/String;IIIC)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_cn_jesse_studio_jni_StudioJni__1serial_1port_1open
(JNIEnv *, jobject, jstring, jint, jint, jint, jchar);
/*
* Class: cn_jesse_studio_jni_StudioJni
* Method: _serial_port_close
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_cn_jesse_studio_jni_StudioJni__1serial_1port_1close
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif</span>
3.在cpp文件中实现之前在jni中声明出来的native方法.这里只是简单的接收一个int数据返回一个int数据.参数中的JNIEnv 指针指向一个函数指针表,通过该指针可以访问其中方法.jclass 在该方法是静态的情况下是是一个类对象的引用,jclass在该方法是实例的情况下代表的是被调用方法所属类的引用.
<span style="font-family:Microsoft YaHei;">JNIEXPORT jint JNICALL media_camera_open(JNIEnv *env,jclass thiz,jint cameraId){
LOGI(CAMERA_TAG, "media_camera_open");
int status = -1;
return status;
}</span>
4.在native中声明jni方法,绑定jni声明方法和本地实现方法,注册jni类,并实现加载Jni方法.
<span style="font-family:Microsoft YaHei;">static const char* const cameraClassPathName = "cn/jesse/studio/jni/StudioJni";
static JNINativeMethod jniMethods[] = {
{"_camera_open", "(I)I", (void *) media_camera_open},
{"_serial_port_open", "(Ljava/lang/String;IIIC)Ljava/io/FileDescriptor;", (void *) serial_port_open},
{"_serial_port_close", "()I", (void *) serial_port_close}
};</span>
<span style="font-family:Microsoft YaHei;">int register_cn_jesse_studio_jni_studioJni(JNIEnv* env){
return AndroidRuntime::registerNativeMethods(env, cameraClassPathName, jniMethods,sizeof(jniMethods) / sizeof(jniMethods[0]));
}</span><span style="font-family:Microsoft YaHei;">static int registerNatives(JNIEnv* env){
if (register_cn_jesse_studio_jni_studioJni(env) < 0){
LOGE(JNILOADER_TAG, "ERROR: registerNatives failed\n");
return JNI_FALSE;
}
return JNI_TRUE;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE(JNILOADER_TAG, "ERROR: GetEnv failed\n");
goto bail;
}
if (env == NULL || registerNatives(env) != JNI_TRUE) {
LOGE(JNILOADER_TAG, "JniLoad ERROR: registerNatives failed, env=%p", env);
goto bail;
}
LOGI(JNILOADER_TAG, "JniLoad JNI Load Success");
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail: return result;
}</span>
5.返回值参数Jni映射.
| Java 类型 | 本地类型 | 描述 |
| boolean | jboolean | C/C++8位整型 |
| byte | jbyte | C/C++带符号的8位整型 |
| char | jchar | C/C++无符号的16位整型 |
| short | jshort | C/C++带符号的16位整型 |
| int | jint | C/C++带符号的32位整型 |
| long | jlong | C/C++带符号的64位整型e |
| float | jfloat | C/C++32位浮点型 |
| double | jdouble | C/C++64位浮点型 |
| Object | jobject | 任何Java对象,或者没有对应java类型的对象 |
| Class | jclass | Class对象 |
| String | jstring | 字符串对象 |
| Object[] | jobjectArray | 任何对象的数组 |
| boolean[] | jbooleanArray | 布尔型数组 |
| byte[] | jbyteArray | 比特型数组 |
| char[] | jcharArray | 字符型数组 |
| short[] | jshortArray | 短整型数组 |
| int[] | jintArray | 整型数组 |
| long[] | jlongArray | 长整型数组 |
| float[] | jfloatArray | 浮点型数组 |
| double[] | jdoubleArray | 双浮点型数组 |
表B
| 函数 | Java 数组类型 | 本地类型 |
| GetBooleanArrayElements | jbooleanArray | jboolean |
| GetByteArrayElements | jbyteArray | jbyte |
| GetCharArrayElements | jcharArray | jchar |
| GetShortArrayElements | jshortArray | jshort |
| GetIntArrayElements | jintArray | jint |
| GetLongArrayElements | jlongArray | jlong |
| GetFloatArrayElements | jfloatArray | jfloat |
| GetDoubleArrayElements | jdoubleArray | jdouble |
表C
| 函数 | 描述 |
| GetFieldID | 得到一个实例的域的ID |
| GetStaticFieldID | 得到一个静态的域的ID |
| GetMethodID | 得到一个实例的方法的ID |
| GetStaticMethodID | 得到一个静态方法的ID |
表D
| Java 类型 | 符号 |
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | L |
| float | F |
| double | D |
| void | V |
| objects对象 | Lfully-qualified-class-name;L类名 |
| Arrays数组 | [array-type [数组类型 |
| methods方法 | (argument-types)return-type(参数类型)返回类型 |
本文详细介绍了Java本地方法的声明关键字Native及其作用,如何使用jni命令生成JNI接口文件,以及如何在C++文件中实现这些接口。此外,文章还讨论了Java与本地方法之间的交互过程,并提供了实例代码来辅助理解。
7636

被折叠的 条评论
为什么被折叠?



