JNI註冊Native方法的步驟: java
一、 Java層有五個Native方法: 數組
DsmccDownloader類下面有五個native方法 jvm
public native voidloadcancel(int handle); private native boolean init(); private native void setCurrentFrequency(int freq); private native int loadDir(XXXXXX); private native int loadfile(XXXXX);
二、 JNI層添加native數組: 函數
數組形式={native方法名稱,(參數類型列表)返回值類型,JNI層方法名稱} spa
static JNINativeMethod gDSMCCNativeMethod[] = { { "loadDir", "(JJIII[B[BLdsmccdownloadservice/DsmccDownloaderListener;)I", (void*)JNI_LoadDir, }, { "loadfile", "(JJIII[BLjava/io/FileDescriptor;Ldsmccdownloadservice/DsmccDownloaderListener;)I", (void*)JNI_LoadFile, }, { "loadcancel", "(I)V", (void*)JNI_LoadCancel, }, { "init", "()Z", (void*)JNI_InitDSMCC, }, { 「setCurrentFrequency", "(I)V", (void*)JNI_SetCurrentFrequency, }, };
三、 Native方法註冊 線程
當Java層調用到 System.loadLibrary("DSMCCDownload");將調用到 JNI中的JNICALL code
static JavaVM* gvm = NULL;//全局變量用於保存JavaVM JNI_OnLoad(JavaVM*vm, void* reserved)完成Native方法的註冊: JNIEnv* env = NULL; jclass clazz = NULL; if((*vm)->GetEnv(vm, (void**)&env ,JNI_VERSION_1_4) !=JNI_OK){//獲取Java 版本 return -1; } //加載有Native方法的Java類 clazz = (*env)->FindClass(env,"dsmccdownloadservice/DsmccDownloader"); //註冊Native方法 if((*env)->RegisterNatives(env,clazz, gDSMCCNativeMethod, 5) < 0) { return -1; } gvm = vm;//保存Jvm
JNI註冊回調方法的步驟: ip
Ø Java層回調方法: 資源
public interface DsmccDownloaderListener { public void doNotifyStart(String path); public void doNotifyFinish(String path, int isSuccess); public void doNotifyDirInfo(String[] path); }
1.JNI層爲每一個方法添加methodID. 原型
static jmethodID DirTask_doNotifyStart_methodID = NULL;
static jmethodID DirTask_doNotifyFinish_methodID = NULL;
static jmethodID DirTask_doNotifyDirInfo_methodID = NULL;
2. Java層調用init()方法,實現回調方法的註冊:
JNIEXPORTjboolean JNICALL JNI_InitDSMCC(JNIEnv* env, jobject thiz) { jbooleanret = JNI_TRUE; jclass class = NULL; class = (*env)->FindClass(env,"dsmccdownloadservice/DsmccClient$DirTask"); DirTask_doNotifyStart_methodID= (*env)->GetMethodID(env, class,"doNotifyStart", "(Ljava/lang/String;)V"); DirTask_doNotifyFinish_methodID= (*env)->GetMethodID(env, class,"doNotifyFinish", "(Ljava/lang/String;I)V"); DirTask_doNotifyDirInfo_methodID= (*env)->GetMethodID(env, class,"doNotifyDirInfo", "([Ljava/lang/String;)V"); }
3. 回調方法的調:以doNotifyFinish爲例:
static voidJNIDSMCCDownloadReq_doNotifyFinish(JNIDSMCCDownloadReq* req, int reason, char* path) { JNIEnv*env = NULL; jstringpath_obj = NULL; if((*gvm)->AttachCurrentThread(gvm, &env, NULL) < 0) { return ; } path_obj= (*env)->NewStringUTF(env, path); assert(path_obj!= NULL); (*env)->CallVoidMethod(env, req->listener,DirTask_doNotifyFinish_methodID, path_obj, reason); (*gvm)->DetachCurrentThread(gvm); }
JNI註冊自定義Java回調方法
1.Java原型方法:
class DsmccClient{ class FDTaskextends Task { FDTask() {} public void writeDataByFD(FileDescriptor mFileDescriptor, String buf, String path) { XXXXXXXXXXXXX; } }
2. JNI實現:
[1] 建立全局變量MethodID
static jmethodID FDTask_writeDataByFD_methodID =NULL;
[2]構造Jclass爲獲得jobject,jmethodID
class = (*env)->FindClass(env,"dsmccdownloadservice/DsmccClient$FDTask");
[3]構造jobject;再此以前須要先獲得該類的構造函數:
static jobject fdTaskObject =NULL; jmethodID init =(*env)->GetMethodID(env,class,"<init>","(Ldsmccdownloadservice/DsmccClient;)V"); jobject obj = (*env)->NewObject(env,class, init,NULL); fdTaskObject = (*env)->NewGlobalRef(env,obj);
在此處構造全局jobject是由於MethodID是全局變量,他們須要在同一個線程中建立,使用的時候才能匹配成功。
[4] 構造MethodID:
FDTask_writeDataByFD_methodID =(*env)->GetMethodID(env,class,"writeDataByFD","(Ljava/io/FileDescriptor;Ljava/lang/String;Ljava/lang/String;)V");
[5]調用回調方法:
(*gvm)->AttachCurrentThread(gvm,&env,NULL) ;//激活Jvm buf_jstring= (*env)->NewStringUTF(env, buf);//參數轉換 (*env)->CallVoidMethod(env,fdTaskObject,FDTask_writeDataByFD_methodID,req->mFileDescriptor,buf_jstring,path_jstring); (*gvm)->DetachCurrentThread(gvm);//關閉jvm其中req->mFileDescriptor:jobject類型
buf_jstring,path_jstring:jstring類型,即C層的char*轉換獲得。
[6]釋放資源:
全局資源須要進行釋放: (*env)->DeleteGlobalRef(env,fdTaskObject);
Ø 注意事項: