Android JNI-c/c++呼叫java方法
阿新 • • 發佈:2018-12-29
在使用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,這樣基本不會出錯。
本人也就是剛接觸jni,本著總結經驗的心態,寫下部落格稍微記錄一下,有錯誤或者不詳細的地方,也請各位大神指點。