原創做品,容許轉載,轉載時請務必以超連接形式標明文章 原始出處 、做者信息和本聲明。不然將追究法律責任。http://ticktick.blog.51cto.com/823160/1358558java
JNI是Java Native Interface的縮寫,是Java平臺的重要特性,使得Java代碼能夠方便地與C/C++代碼編譯生成的動態連接庫進行交互。本文主要給出一份示例代碼(工程文件見附件),描述如何在Android的JNI層開啓一個線程,並在線程中回調Java層的函數。android
代碼主要分爲Java層(java代碼)和JNI層(c語言代碼),首先看看Java層的代碼(Native.java)。函數
如上所示,Java層與JNI層的接口代碼主要封裝在Native類中,該類定義了三個native函數,分別完成jni庫的初始化,調用jni層開啓線程,調用jni層關閉線程等功能。而且提供一個回調函數(onNativeCallback),供jni層調用,並在回調函數中打印count的值。spa
再看看JNI層是如何開啓線程並回調Java層的(native.c),關鍵的地方都在代碼中進行了註釋:線程
native C實現:3d
1. 頭文件包含和全局變量的定義對象
2. 初始化函數的實現blog
3. 開啓關閉線程的實現接口
4. 線程的實現(關鍵)get
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端的函數,進行回調。