原创作品,允许转载,转载时请务必以超链接形式标明文章 、作者信息和本声明。否则将追究法律责任。
JNI是Java Native Interface的缩写,是Java平台的重要特性,使得Java代码可以方便地与C/C++代码编译生成的动态链接库进行交互。本文主要给出一份示例代码(工程文件见附件),描述如何在Android的JNI层开启一个线程,并在线程中回调Java层的函数。
代码主要分为Java层(java代码)和JNI层(c语言代码),首先看看Java层的代码(Native.java)。
如上所示,Java层与JNI层的接口代码主要封装在Native类中,该类定义了三个native函数,分别完成jni库的初始化,调用jni层开启线程,调用jni层关闭线程等功能。并且提供一个回调函数(onNativeCallback),供jni层调用,并在回调函数中打印count的值。
再看看JNI层是如何开启线程并回调Java层的(native.c),关键的地方都在代码中进行了注释:
native C实现:
1. 头文件包含和全局变量的定义
2. 初始化函数的实现
3. 开启关闭线程的实现
4. 线程的实现(关键)
native C++实现
#include <jni.h>
#include <android/log.h>#include <pthread.h>#include <unistd.h>#define TAG "JniNative"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)JavaVM *gJavaVM;jobject gJavaObj;int volatile gIsThreadStop = 0;static const char *classPath = "com/jni/test/JniNativeCallback";static void* native_thread_exec(void *arg){ LOGI("nativeThreadExec"); JNIEnv *env; //get env From gJavaVm gJavaVM->AttachCurrentThread(&env,NULL); //get Java class by classPath// jclass thiz = env->FindClass(classPath); jclass thiz = env->GetObjectClass(gJavaObj); //get Java method from thiz jmethodID nativeCallback = env->GetMethodID(thiz,"nativeCallback","(I)V"); int count = 0; while(!gIsThreadStop) { sleep(2); //env->CallVoidMethod(thiz,nativeCallback,count++); env->CallVoidMethod(gJavaObj,nativeCallback,count++); } gJavaVM->DetachCurrentThread(); LOGI("thread stoped");}JNIEXPORT void JNICALL native_init(JNIEnv *env,jobject thiz){ LOGI("native_init"); gIsThreadStop = 0; env->GetJavaVM(&gJavaVM); gJavaObj = env->NewGlobalRef(thiz);}JNIEXPORT void JNICALL native_thread_start(JNIEnv *env,jobject jthiz){ LOGI("native_thread_start"); gIsThreadStop = 0; pthread_t id; if(pthread_create(&id,NULL,native_thread_exec,NULL)!=0) { LOGI("native thread create fail"); return; } LOGI("native thread creat success");}JNIEXPORT void JNICALL native_thread_stop(JNIEnv *env,jobject jthiz){ gIsThreadStop = 1; LOGI("native_thread_stop");}static JNINativeMethod methods[] = { {"nativeInit","()V",(void*)native_init}, {"nativeThreadStart","()V",(void*)native_thread_start}, {"nativeThreadStop","()V",(void*)native_thread_stop}};jint JNI_OnLoad(JavaVM *vm, void *reserve){ LOGI("JNI_OnLoad"); JNIEnv *env; if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK) { return -1; } jclass jthiz = env->FindClass(classPath); if(env->RegisterNatives(jthiz,methods,sizeof(methods)/sizeof(methods[0]))<0) { return -1; } return JNI_VERSION_1_4;}
由上述代码可以看到,JNI层通过pthread库完成了线程的创建,需要特别注意的是,JNI层的线程中,必须通过全局的JavaVM来获取到环境变量,也必须通过全局的jobject获取java类对象,从而找到java端的函数,进行回调。