JNI native方法以及回調方法的實現

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);

Ø  注意事項:

  1. 若當前回調方法處於某個類下面,必須先獲得該類的構造方法。
  2. MethodID和object必須處於同一個線程下建立
  3. 參數類型的轉換,若爲引用類型需加上L。
相關文章
相關標籤/搜索