欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android JNI-c/c++调用java方法

程序员文章站 2022-03-13 14:19:59
android jni-c/c++调用java方法,在使用ndk开发的时候,java调用c/c++方法是必须要的。但是很多时候,c/c++有callback需要反馈给java的时候...

android jni-c/c++调用java方法,在使用ndk开发的时候,java调用c/c++方法是必须要的。但是很多时候,c/c++有callback需要反馈给java的时候(比如im通讯登录成功信息和一些异常信息),就需要c/c++调用java方法了。
在看这篇文章之前,必须对jni有一些基础的了解,比如java调用c/c++方法,java和c/c++ jni在一些基本类型上的对应(int对应jint等)。
那么现在介绍一下c/c++调用java方法的基本步骤:

1.需要把java方法所在类的实例通过jni方法传到c/c++

java:jni, 这是c需要回调的java方法,然后通过调用自身init()方法,把java实例传到c层

class jni {
public native void init(jni obj);
public void error(int code) {
        log.i("jni", "c++ call error ");
    }
}

c:这里把java传递进来的objlistener,保存到c的jniobj结构体内。

jniexport jint jnicall java_com_arcvideo_rtcmessage_jni_init(
    jnienv *env, 
    jobject oj, 
    jobject objlistener,
    )
{
    if(objlistener == mnull){
            mvlog("objlistener is null");
        }else
        {
            mvlog("get java obj");
            jniobj->g_obj = env->newglobalref(objlistener);
        }
    return res;
}
typedef struct _tagjniobj{//这个是刚才保存java实例的结构体,在还有其他参数
    jmethodid jni_error;
    javavm* g_jvm;
    jnienv* g_threadenv;
    jclass g_class;
    jobject g_obj;
    mhandle g_h;
}jniobj;
static jniobj* jniobj = mnull;

2.在c层拿到java class

c:通过jni提供的findclass方法和完整类名,可以拿到class引用

static const char* const dl_class_name = "com/arcvideo/rtcmessage/jni";
jniobj->g_class = env->findclass(dl_class_name);

3.在c层拿到java method

c:根据刚才拿到的java class引用有jni提供的getmethodid方法,和方法名,入参,就可以拿到method引用

// error
        jniobj->jni_error = env->getmethodid(jniobj->g_class, "error", 
        "(i)v");
        if(jniobj->jni_error == mnull){
            mvlog("create jni_error is error");
        }

4.调用method

c:在需要调用的地方调用这个java方法,

static void error(mdword code, mvoid* pobj)
{
    mvlog("rtcmessagejni error is in code : %d", code );
    if(jniobj->g_threadenv == mnull)
    {
        mvlog("attach current thread start");
        jniobj->g_jvm -> attachcurrentthread(&jniobj->g_threadenv, mnull);

        if(jniobj->g_threadenv == mnull){
            mvlog("attach current thread is error");
            return;
        }
    }
    if(jniobj && jniobj->jni_error){
        mvlog("rtcmessagejni error is called");
        //这里是最关键的调用过程,通过jni提供的callvoidmethod,来调用,加入参数,class引用,method应用,已经入参,这样调用java方法就完成了。
        jniobj->g_threadenv->callvoidmethod(jniobj->g_obj, jniobj->jni_error, 
        (int)code);
    }

    if(jniobj->g_jvm){
        mvlog("rtcmessagejni error method detach");
        jniobj->g_jvm->detachcurrentthread();
        jniobj->g_threadenv = mnull;
    }
}

这里在调用java方法的时候调用了,attachcurrentthread和detachcurrentthread方法,这是必须的,如果不调用attachcurrentthread就拿不到线程的引用,会报错误。然后在调用结束的时候要调用detachcurrentthread,也就是释放线程。根据个人经验,最好每次调用java方法结束的时候都调用detachcurrentthread,这样基本不会出错。