zoukankan      html  css  js  c++  java
  • JNI中C调用Java方法

    背景需求

      我们需要在JNI的C代码调用Java代码。实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用。

    JNI关键方法讲解。

    1. 在同一个类中,调用其他方法

    JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1
      (JNIEnv * env, jobject obj){
        //在c代码里面调用java代码里面的方法
        // java 反射
        //1 . 找到java代码的 class文件
        //    jclass      (*FindClass)(JNIEnv*, const char*);
        jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
        if(dpclazz==0){
            LOGI("find class error");
            return;
        }
        LOGI("find class ");
    
        //2 寻找class里面的方法
        //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
        if(method1==0){
            LOGI("find method1 error");
            return;
        }
        LOGI("find method1 ");
        //3 .调用这个方法
        //    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        (*env)->CallVoidMethod(env,obj,method1);
    }

     注意: 看红色的内容,如何获得呢? 这个是函数的签名。函数签名借住命令 javap -p -s(这两个参数一定要加入)来获得,放到第二个参数即可。

    注意:

    1. 要加入上面的参数 -p -s

    2. signature后面有时候带“;”,不要丢掉。 主要要仔细检查

    示例:

    void notifyOnStatusReport(int32_t status)
    {
        if (curEnv != NULL && curObj != NULL) {
            jclass clsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/LiveNativeSender");
            jfieldID mUsercommandCallbackEventListnerFieldId = curEnv->GetFieldID(clsstring,"mStatusEventListener","Lcom/baidu/tieba/liveSdk/publisher/OnStatusEventListener;");
            jobject mUsercommandCallbackEventListner = curEnv->GetObjectField(curObj,mUsercommandCallbackEventListnerFieldId);
            
            jclass onStatusEventListenerClsstring = curEnv->FindClass("com/baidu/tieba/liveSdk/publisher/OnStatusEventListener");
            jmethodID onStatusReport = curEnv->GetMethodID(onStatusEventListenerClsstring, "onStatusReport",
                                             "(I)V");
            curEnv->CallVoidMethod(mUsercommandCallbackEventListner, onStatusReport, status);
        }
    }

    这样就可以调用DataProvider中的helloFromJava方法了。

    2. 上面的方法是调用的返回值为void的java方法。如果想调用其他类型的。JNI中还提供的许多其他返回类型的方法。

        jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
        jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jobject     (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jboolean    (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
        jboolean    (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jboolean    (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
        jbyte       (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jbyte       (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jchar       (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
        jchar       (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jchar       (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jshort      (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
        jshort      (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jshort      (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
        jint        (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jint        (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jlong       (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
        jlong       (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        jlong       (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
        jfloat      (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
        jfloat      (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
        jfloat      (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
        jdouble     (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__;
        jdouble     (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__;
        jdouble     (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__;
        void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        void        (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
        void        (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);

    3. 如果java中的方法是静态的,就需要调用GetStaticMethodID 和 CallStaticVoidMethod 方法。

    JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod4
      (JNIEnv * env, jobject obj){
          //1 . 找到java代码的 class文件
            //    jclass      (*FindClass)(JNIEnv*, const char*);
            jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
            if(dpclazz==0){
                LOGI("find class error");
                return;
            }
            LOGI("find class ");
    
            //2 寻找class里面的方法
            //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
            // 注意 :如果要寻找的方法是静态的方法 那就不能直接去获取methodid
            //jmethodID method4 = (*env)->GetMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V");
            //    jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
            jmethodID method4 = (*env)->GetStaticMethodID(env,dpclazz,"printStaticStr","(Ljava/lang/String;)V");
            if(method4==0){
                LOGI("find method4 error");
                return;
            }
            LOGI("find method4 ");
    
            //3.调用一个静态的java方法
            //    void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
            (*env)->CallStaticVoidMethod(env,dpclazz,method4,(*env)->NewStringUTF(env,"static haha in c"));
    }

    4. 如果C调用的Java方法不在一个类中。

    分析:JNI提供的方法都有两个参数:(JNIEnv *env , jobject obj)。 env是JNI提供的方法集合。 obj是上线文。下面的例子的obj不是所需要的上下午,所以要重新创建。

    //obj DemoActivity
     JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DemoActivity_call_1dp_1method1
      (JNIEnv * env, jobject obj){
        //在c代码里面调用java代码里面的方法
            // java 反射
            //1 . 找到java代码的 class文件
            //    jclass      (*FindClass)(JNIEnv*, const char*);
            jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
            if(dpclazz==0){
                LOGI("find class error");
                return;
            }
            LOGI("find class ");
    
            //2 寻找class里面的方法
            //   jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
            jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
            if(method1==0){
                LOGI("find method1 error");
                return;
            }
            LOGI("find method1 ");
            //3 .调用这个方法
            //    void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
            //    jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
            //  jobject     (*AllocObject)(JNIEnv*, jclass);
            jobject dpobj= (*env)->AllocObject(env,dpclazz);
    
            (*env)->CallVoidMethod(env,dpobj,method1);
    }

    5. 提示

    为了避免4中的内容,我们尽量让C要调用的Java方法在同一个类中

  • 相关阅读:
    [原创]Windows 7 下成功添加网络共享HP打印机
    [原创]PDFCreator自动保存及文件名带空格、后缀名丢失的解决方法(Windows 7通过)
    [原创]U872客户端“system.net.sockets.socketexception”的解决方法
    [转载]Windows 7默认共享无法访问
    [转载]使Excel不显示0值的三招
    [原创]使用空密码远程桌面连接
    分布式架构理论
    ffmpeg重要函数和结构体整理
    es~存储部分字段
    es~text与keyword的选择
  • 原文地址:https://www.cnblogs.com/xitang/p/4174619.html
Copyright © 2011-2022 走看看