private static native final void native_init();
那是怎么知道是這個方法的呢?
MediaRecorder.java位于android.media包中,,所以native_init的全路徑是android.media.MediaRecorder.native_init,。顯而易見,將“.”替換成“_”就是jni函數(shù)的名字了,。這里說的就是JNI函數(shù)的注冊問題,,就是將java層的native函數(shù)和JNI層函數(shù)的具體實現(xiàn)關(guān)聯(lián)起來。
JNI函數(shù)的注冊有兩種方法,,一種是靜態(tài)方法,,需要用javah為每個聲明了native函數(shù)的java類編譯出的class文件生成一個頭文件,另一種是動態(tài)注冊,通過數(shù)據(jù)結(jié)構(gòu)保存關(guān)聯(lián)關(guān)系實現(xiàn)注冊,,這里主要介紹動態(tài)注冊,。
動態(tài)注冊
動態(tài)注冊需要一個數(shù)據(jù)結(jié)構(gòu)去保存相關(guān)的關(guān)聯(lián)關(guān)系,這個結(jié)構(gòu)(在jni.h中聲明)是:
typedef struct { const char* name; //java中native函數(shù)的名字 const char* signature; //Java函數(shù)的簽名信息,,用字符串表示,,是參數(shù)類型和返回值類型的組合 void* fnPtr; } JNINativeMethod; //JNI層函數(shù)的函數(shù)指針,void*類型
在JNI層中(android_media_MediaRecorder.cpp)是如何使用這個結(jié)構(gòu)體的:
static JNINativeMethod gMethods[] = { {"native_init","()V",(void *)android_media_MediaRecorder_native_init}, }; // This function only registers the native methods, and is called from // JNI_OnLoad in android_media_MediaPlayer.cpp int register_android_media_MediaRecorder(JNIEnv *env) //什么時候會調(diào)用呢,?后面介紹 { return AndroidRuntime::registerNativeMethods(env, "android/media/MediaRecorder", gMethods, NELEM(gMethods)); }
利用AndroidRuntime類提供的registerNativeMethods函數(shù)完成注冊工作
/* * Register native methods using JNI. */ /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) //位于AndroidRuntime.cpp { return jniRegisterNativeMethods(env, className, gMethods, numMethods); } /* * Register native JNI-callable methods. * * "className" looks like "java/lang/String". */ int jniRegisterNativeMethods(JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods) //位于JNIHelp.c { jclass clazz; LOGV("Registering %s natives\n", className); clazz = (*env)->FindClass(env, className); if (clazz == NULL) { LOGE("Native registration unable to find class '%s'\n", className); return -1; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { LOGE("RegisterNatives failed for '%s'\n", className); return -1; } return 0;}
實際上所有的注冊工作最后就是調(diào)用:
(*env)->RegisterNatives(env,clazz,gMethods,numMethods)完成,。那么這些動態(tài)注冊的函數(shù)是什么時候和什么地方調(diào)用的呢?其實,,當Java層通過System.loadLibrary加載完JNI動態(tài)庫之后,,就會查找?guī)熘薪蠮NI_OnLoad函數(shù),通過調(diào)用它完成動態(tài)注冊的工作,。
externint register_android_media_MediaRecorder(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, void* reserved) //JavaVM* vm是Java虛擬機在JNI層的對象,,每一個java進程只有一個JVM { JNIEnv* env = NULL; //每一個線程有一個JNIEnv對象 jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } if (register_android_media_MediaRecorder(env) < 0) { //動態(tài)注冊MediaRecorder的JNI函數(shù) LOGE("ERROR: MediaRecorder native registration failed\n"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; bail: return result; }
|
|
來自: 清凈明誨 > 《Android開發(fā)》