1、定义native方法并加载动态链接库:
public class HelloJni extendsActivity
{
@Overridepublic voidonCreate(Bundle savedInstanceState)
{super.onCreate(savedInstanceState);
TextView tv= new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}public native String stringFromJNI();
public nativeString unimplementedStringFromJNI();static {
System.loadLibrary("hello-jni");
}
}
2、实现native方法:
#include #includejstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv*env,
jobject thiz )
{return (*env)->NewStringUTF(env, "Hello from JNI !"); //in c
returnenv->NewStringUTF("Hello from JNI !"); //in c++
}
若要定义静态方法:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv* env, jclass clazz);
头文件可以用javah工具生成:
进入命令行,切换到项目的bin目录下的classes下面,执行 javah -classpath . -jni 包.类名。
或者:cd到src目录中,执行javah 包.类名
3、数据
原始数据类型:
引用数据类型:
4、字符窜的操作:
1)新建字符串:
jstring javaString;
javaString = (*env)->NewStringUTF(env, "Hello World!");
2)把java string转换成c string
const jbyte*str;
jboolean isCopy;
str= (*env)->GetStringUTFChars(env, javaString, &isCopy);if (0 !=str) {
printf("Java string: %s", str);if (JNI_TRUE ==isCopy) {
printf("C string is a copy of the Java string.");
}else{
printf("C string points to actual string.");
}
(*env)->ReleaseStringUTFChars(env, javaString, str);
5、数组的操作:
1)新建java数组:
jintArray javaArray;
javaArray= (*env)->NewIntArray(env, 10);if (0 !=javaArray) {/*You can now use the array.*/}
2)获取数组的值:
jint nativeArray[10];
//将java array 复制到 c array
(*env)->GetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
//将 c array 还原城 java array
(*env)->SetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
获取数组指针:
jint*nativeDirectArray;
jboolean isCopy;
nativeDirectArray= (*env)->GetIntArrayElements(env, javaArray, &isCopy);
//...
(*env)->ReleaseIntArrayElements(env, javaArray, nativeDirectArray, 0);
6、C\C++获取java成员变量
public classJavaClass {/**Instance field*/
private String instanceField = "Instance Field";/**Static field*/
private static String staticField = "Static Field";
...
}
1)获取Field ID
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;");
2)获取Static Field
jstring staticField;
staticField= (*env)->GetStaticObjectField(env, clazz, staticFieldId);
7、C\C++调用java函数
public classJavaClass {/*** Instance method.*/
privateString instanceMethod() {return "Instance Method";
}/*** Static method.*/
private staticString staticMethod() {return "Static Method";
}
...
}
1)获取Method ID:
成员函数:
jmethodID instanceMethodId;
instanceMethodId= (*env)->GetMethodID(env, clazz,"instanceMethod", "()Ljava/lang/String;");
静态函数:
jmethodID staticMethodId;
staticMethodId= (*env)->GetStaticMethodID(env, clazz,"staticMethod", "()Ljava/lang/String;");
2)调用:
jstring instanceMethodResult;
instanceMethodResult= (*env)->CallStringMethod(env,
instance, instanceMethodId);
变量和函数的描述符:
javap工具可以提取从编译过的class files 中提取这些描述符:
javap –classpath bin/classes –p –s com.example.hellojni.HelloJni
8、处理异常:
public classJavaClass {/*** Throwing method.*/
private void throwingMethod() throwsNullPointerException {throw new NullPointerException("Null pointer");
}/*** Access methods native method.*/
private native voidaccessMethods();
}
jthrowable ex;
...
(*env)->CallVoidMethod(env, instance, throwingMethodId);
ex= (*env)->ExceptionOccurred(env);if (0 !=ex) {
(*env)->ExceptionClear(env);/*Exception handler.*/}
从c\c++抛异常:
jclass clazz;
...
clazz= (*env)->FindClass(env, "java/lang/NullPointerException");if (0 ! =clazz) {
(*env)->ThrowNew(env, clazz, "Exception message.");
}
9、本地和全局变量:
1)本地变量在函数结束时自动释放内存:
jclass clazz;
clazz= (*env)->FindClass(env, "java/lang/String");
2)新建全局变量:
jclass localClazz;
jclass globalClazz;
...
localClazz= (*env)->FindClass(env, "java/lang/String");
globalClazz= (*env)->NewGlobalRef(env, localClazz);
...
(*env)->DeleteLocalRef(env, localClazz);
3)释放全局变量:
(*env)->DeleteGlobalRef(env, globalClazz);
4)弱全局引用:
弱全局引用可以被内存自动回收:
jclass weakGlobalClazz;
weakGlobalClazz= (*env)->NewWeakGlobalRef(env, localClazz);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.*/}
(*env)->DeleteWeakGlobalRef(env, weakGlobalClazz);
10、线程:
synchronized(obj) {/*Synchronized thread-safe code block.*/}
if (JNI_OK == (*env)->MonitorEnter(env, obj)) {/*Error handling.*/}/*Synchronized thread-safe code block.*/
if (JNI_OK == (*env)->MonitorExit(env, obj)) {/*Error handling.*/}
native线程不能和java直接通信,必须先绑定到javaVM
JavaVM*cachedJvm;
...
JNIEnv*env;
.../*Attach the current thread to virtual machine.*/(*cachedJvm)->AttachCurrentThread(cachedJvm, &env, NULL);/*Thread can communicate with the Java application
using the JNIEnv interface.*/
/*Detach the current thread from virtual machine.*/(*cachedJvm)->DetachCurrentThread(cachedJvm);