JNI-本地通信

Eclipse添加一键调用javah生成jni的头文件:
Run->External Tools External Tools Configurations->Program->New launch configuration ,填写:
Location:${system_path:javah}

Working Directory:${project_loc}\src

Arguments:(javah命令)-classpath .;./classes -d “ projectloc"jni {java_type_name}
.;./classes为class文件目录
-d “${project_loc}”为生成.h文件存放位置
JNI-本地通信_第1张图片
如要javah文件改变立刻刷新,则:
JNI-本地通信_第2张图片
Comman->DisPlay in favorite menu,勾上

选中要转化的java文件:
Run->External Tools->Generate c and c++ Header File
在项目目录下会发现生成了.h的头文件

JNIEnv:一个指向java类可用函数表的指针,java对象引用类实例
public native String stringFromJNI();
方法依赖于类的实例,传入类的实例thiz作为第二个参数,对应的头文件:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv * env, jobject thiz);

public static native String stringFromJNI();
静态方法不依赖于类的实例,传入类的Class作为第二个参数,对应的头文件:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv * env, jclass clazz);

Java数据类型

基本数据类型boolean, byte, char, short, int, long, float,double
引用数据类型String, arrays, 其它
JNI-本地通信_第3张图片
JNI-本地通信_第4张图片

String操作:
string为引用类型,string对象不可改变,jni转换为c字符串,支持Unicode 和 UTF-8两套编码通过JNIEnv的接口指针来处理。

GetStringUTFChars将jstring转换成为UTF-8格式的char*
GetStringChars将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars释放指向UTF-8格式的char*的指针
ReleaseStringChars释放指向Unicode格式的char*的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取 UTF-8格式的char*的长度 
GetStringLength获取Unicode格式的char*的长 度

Array

jintArray javaArray;
javaArray = (*env)->NewIntArray(env, 10);
if (0 != javaArray) {
/* You can now use the array. */
}

复制到缓冲区修改array

jint nativeArray[10];
(*env)->GetIntArrayRegion(env, javaArray, 0, 10, nativeArray);

返回修改结果

(*env)->SetIntArrayRegion(env, javaArray, 0, 10, nativeArray);

当数组过大,复制导致性能问题,则提供获得一个数组元素直接指针

jint* nativeDirectArray;
jboolean isCopy;
nativeDirectArray = (*env)->GetIntArrayElements(env, javaArray, &isCopy);
(*env)->ReleaseIntArrayElements(env, javaArray, nativeDirectArray, 0);

0:返回内容,并释放本地array
JNI_COMMIT:返回内容不释放,用于周期性更新
JNI_ABORT:释放array并不复制

isCopy参数传入的是一个jboolean的指针,其值可以为NULL、JNI_TRUE、JNI_FLASE。
如果为JNI_TRUE则表示在本地开辟内存,然后把Java中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。如果为JNI_FALSE,则直接返回指向Java中String的内存指针。这时不要改变这个内存中的内容,这将破坏String在Java中始终是常量的规则。
如果是NULL,则表示不关心是否拷贝字符串。

字节缓冲区

根据给定的Ç字节数组创建新的字节缓冲区,需要释放

unsigned char* buffer = (unsigned char*) malloc(1024);
...
jobject directBuffer;
directBuffer = (*env)->NewDirectByteBuffer(env, buffer, 1024);

直接字节缓冲区,也可以在Java应用程序中创建。本机代码可以使用
GetDirectBufferAddress函数调用来获取本地字节数组的内存地址,

unsigned char* buffer;
buffer = (unsigned char*) (*env)->GetDirectBufferAddress(env,
directBuffer);

获取类对象:

一个包含私有静态和变量的实例类

public class JavaClass {
/** Instance field */
private String instanceField = "Instance Field";
/** Static field */
private static String staticField = "Static Field";
...
}

获取从类对象引用

jclass clazz;
clazz = (*env)->GetObjectClass(env, instance);

获取一个实例字段的字段标识

jfieldID instanceFieldId;
instanceFieldId = (*env)->GetFieldID(env, clazz,
"instanceField", "Ljava/lang/String;");

获取静态字段的字段标识

jfieldID staticFieldId;
staticFieldId = (*env)->GetStaticFieldID(env, clazz,
"staticField", "Ljava/lang/String;");

获取静态字段

jstring staticField;
staticField = (*env)->GetStaticObjectField(env, clazz, staticFieldId);

获取JAVA签名:

javap –classpath bin/classes –p –s com.example.hellojni.HelloJni

创建指向某个对象的局部引用,创建失败返回NULL
jobject NewLocalRef(jobject ref);
删除局部引用
void DeleteLocalRef(jobject obj);
创建指向某个对象的全局引用,创建失败返回NULL
jobject NewGlobalRef(jobject lobj);
删除全局引用
void DeleteGlobalRef(jobject gref);

jclass localClazz;
jclass globalClazz;
...
localClazz = (*env)->FindClass(env, "java/lang/String");
globalClazz = (*env)->NewGlobalRef(env, localClazz);
...
(*env)->DeleteLocalRef(env, localClazz);
(*env)->DeleteGlobalRef(env, globalClazz);

弱全局对象,可被垃圾回收期回收

jclass weakGlobalClazz;
weakGlobalClazz = (*env)->NewWeakGlobalRef(env, localClazz);

(*env)->DeleteWeakGlobalRef(env, weakGlobalClazz);

检查是否被回收

if (JNI_FALSE == (*env)->IsSameObject(env, weakGlobalClazz, NULL)) {
/* Object is still live and can be used. */
} else {
/* Object is garbage collected and cannot be used. */
}

多线程

局部引用Local 不能多线程共享,只有全局引用global才行,JNIEnv接口指针只在相关线程有效,不能缓存和用于其它线程

Java的同步代码块
synchronized(obj) {
/* Synchronized thread-safe code block. */
}
native实现

if (JNI_OK == (*env)->MonitorEnter(env, obj)) {
/* Error handling. */
}
/* Synchronized thread-safe code block. */
if (JNI_OK == (*env)->MonitorExit(env, obj)) {
/* Error handling. */
}

为防止死锁,MonitorEnter应与MonitorExit匹配

在当前虚拟机中创建和停止线程

JavaVM* cachedJvm;
...
JNIEnv* env;
...
(*cachedJvm)->AttachCurrentThread(cachedJvm, &env, NULL);
(*cachedJvm)->DetachCurrentThread(cachedJvm);

学习文档

http://docs.oracle.com/javase/1.5.0/docs/guide/jni/

你可能感兴趣的:(NDK开发笔记)