现在的位置: 首页 > 综合 > 正文

JNI Native和回调方法实现

2018年01月29日 ⁄ 综合 ⁄ 共 4192字 ⁄ 字号 评论关闭

JNI注册Native方法的步骤:

1、 Java层有五个Native方法:

DsmccDownloader类下面有五个native方法

public native voidloadcancel(int handle);

    private native booleaninit();

    private native voidsetCurrentFrequency(int freq);

    private native int loadDir(XXXXXX);

    private native intloadfile(XXXXX);

2、 JNI层添加native数组:

数组形式={native方法名称,(参数类型列表)返回值类型,JNI层方法名称}

static JNINativeMethod gDSMCCNativeMethod[] = {

      {     "loadDir",

           "(JJIII[B[BLipanel/dsmccdownloadservice/DsmccDownloaderListener;)I",

           (void*)JNI_LoadDir,   },

      {     "loadfile",

           "(JJIII[BLjava/io/FileDescriptor;Lipanel/dsmccdownloadservice/DsmccDownloaderListener;)I",

           (void*)JNI_LoadFile,  },

      {     "loadcancel",

           "(I)V",

           (void*)JNI_LoadCancel, },

      {     "init",

           "()Z",

           (void*)JNI_InitDSMCC, },

      {     “setCurrentFrequency",

           "(I)V",

           (void*)JNI_SetCurrentFrequency,   },

};

3、 Native方法注册

当Java层调用到  System.loadLibrary("DSMCCDownload");将调用到 JNI中的JNICALL

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,"ipanel/dsmccdownloadservice/DsmccDownloader");

    if(clazz == NULL) {

      return -1;

   }

     //注册Native方法

   if((*env)->RegisterNatives(env,clazz, gDSMCCNativeMethod, 5) < 0) {

      return -1;

   }

gvm = vm;//保存Jvm

 


 JNI注册回调方法的步骤:

Ø  Java层回调方法:

public interface DsmccDownloaderListener {

        publicvoid doNotifyStart(String path);

        public void doNotifyFinish(String path, int isSuccess);

        publicvoid doNotifyDirInfo(String[]path);

}

Ø  JNI层为每个方法添加methodID.

static jmethodID DirTask_doNotifyStart_methodID = NULL;

static jmethodID DirTask_doNotifyFinish_methodID = NULL;

static jmethodID DirTask_doNotifyDirInfo_methodID = NULL;

 

Ø  Java层调用init()方法,实现回调方法的注册:

 JNIEXPORTjboolean JNICALL JNI_InitDSMCC(JNIEnv* env, jobject thiz) {

    jbooleanret = JNI_TRUE;

   jclass class = NULL;

    class = (*env)->FindClass(env,"ipanel/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"); 

}

 

Ø  回调方法的调:以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回调方法

Ø  Java原型方法:

class DsmccClient{

  class FDTaskextends Task {

       FDTask() {}

publicvoidwriteDataByFD(FileDescriptor mFileDescriptor, String buf,

              String path) { XXXXXXXXXXXXX;}

}

}

Ø  JNI实现:

1.      创建全局变量MethodID

 static jmethodID FDTask_writeDataByFD_methodID =NULL;

2.      构造Jclass为得到jobject,jmethodID

  class = (*env)->FindClass(env,"ipanel/dsmccdownloadservice/DsmccClient$FDTask");

3.      构造jobject;再此之前需要先得到该类的构造函数:

     static jobjectfdTaskObject =NULL;

    jmethodID init =(*env)->GetMethodID(env,class,"<init>","(Lipanel/dsmccdownloadservice/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。

抱歉!评论已关闭.