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,这样基本不会出错。