C++ 全局调用Java方法

作者: ZebraWei | 来源:发表于2019-11-09 18:10 被阅读0次

    版权声明:本文为卫伟学习总结文章,转载请注明出处!
    一、C++主线程调用Java方法

      1. 根据jobject获取jclass(静态方法就不用这一步了)如: jclass clz = env->GetObjectClass(jobj);
    • 2.获取jmethodid 如:jmethodid jmid = env->GetMethodID(clz,"onError","(ILjava/lang/String;)V");
    • 3.调用方法如: jenv->CallVoidMethod(jobj,jmid,code,jmsg)

    签名方法参数类型对应表

    Java类型 类型签名
    boolean Z
    byte B
    char C
    short S
    int I
    long L
    float F
    double D
    L全限定名;,比如String,其签名为Ljava/lang/util/String;
    数组 [类型签名,比如[B

    通过命令获取native方法签名
    在native所在类的class文件目录下,执行命令:
    javap -s ***.class


    二、C++子线程调用Java方法
    由于JniEnv是线程相关的,所以子线程中不能使用创建线程的JniEnv;而JVM是进程相关的,所以可以通过JVM来获取当前线程的JniEnv,然后就可以调用Java的方法了。
    • 1.获取JVM对象: JNI_OnLoad(JavaVM* vm, void *reserved)
      1. 通过JVM获取JniEnv:JNIEnv *env = jvm->AttachCurrentThread(&env,0);
        jvm->DetachCurrentThread();

    C++全局调用Java方法Demo

    //
    // Created by weiwei on 2019/11/9.
    //
    #include "jni.h"
    
    #ifndef MYMUSIC_JAVALISTENER_H
    #define MYMUSIC_JAVALISTENER_H
    
    
    class JavaListener {
    
    public:
    JavaVM *jvm;
    _JNIEnv *jenv;
    jobject jobj;
    jmethodID  jmid;
    
    public:
    JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj);
    ~JavaListener();
    
    /**
     * 1:主线程
     * 2:子线程
     * @param type
     * @param code
     * @param msg
     */
    void onError(int type, int code, const char *msg);
    
    };
    
    
    #endif //MYMUSIC_JAVALISTENER_H
    

    JavaListener.cpp文件

    //
    // Created by weiwei on 2019/11/9.
    //
    #include "JavaListener.h"
    
    JavaListener::JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj) {
    
       jvm = vm;
       jobj = obj;
       jenv = env;
       jclass cls = env->GetObjectClass(jobj);
    
       if(!cls) {
          return;
       }
    
       jmid = env->GetMethodID(cls,"onError","(ILjava/lang/String;)V");
    
       if(!jmid)
         return;
    
    }
    
    void JavaListener::onError(int type, int code, const char *msg) {
    
       if(type == 0)
       {
      JNIEnv *env;
      jvm->AttachCurrentThread(&env, 0);
      jstring jmsg = env->NewStringUTF(msg);
      env->CallVoidMethod(jobj, jmid, code, jmsg);
      env->DeleteLocalRef(jmsg);
    
      jvm->DetachCurrentThread();
      }
      else if(type == 1)
     {
      jstring jmsg = jenv->NewStringUTF(msg);
      jenv->CallVoidMethod(jobj, jmid, code, jmsg);
      jenv->DeleteLocalRef(jmsg);
     }
    } 
    

    JNI实现代码

    #include <jni.h>
    #include <string>
    #include <android/log.h>
    #include "pthread.h"
    #include "AndroidLog.h"
    
    extern "C"
    {
        #include <libavformat/avformat.h>
    }
    
    #include "queue"
    #include "unistd.h"
    
    pthread_t produc;
    pthread_t custom;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    
    #include "JavaListener.h"
    
    JavaVM *jvm;
    JavaListener *javaListener;
    
    pthread_t childThread;
    
    void *childCallback(void *data) {
       JavaListener *javaListener1 = (JavaListener *) data;
    
       javaListener1->onError(0,101,"c++ call java meid from child thread! haha");
       pthread_exit(&childThread);
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_day1_jado_mymusic_ThreadDemo_callbackFromC(JNIEnv *env, jobject instance) {
       javaListener = new JavaListener(jvm,env,env->NewGlobalRef(instance)); //得到全局的 instance
        //javaListener->onError(1,100,"c++ call java meid from main thread!");
       pthread_create(&childThread, NULL, childCallback, javaListener);
    }
    
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void* reserved)
    {
       JNIEnv *env;
       jvm = vm;
       if(vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
       {
        return -1;
       }
       return JNI_VERSION_1_6;
    }
    

    相关文章

      网友评论

        本文标题:C++ 全局调用Java方法

        本文链接:https://www.haomeiwen.com/subject/bclnbctx.html