日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

inflect java_在native线程利用JNI 反射自定义类

發(fā)布時間:2024/3/13 110 豆豆
生活随笔 收集整理的這篇文章主要介紹了 inflect java_在native线程利用JNI 反射自定义类 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

NDK編程中遇到的一些細節(jié)問題,希望對大家有幫助

-----題記

在JNI中,有時候出于業(yè)務(wù)要求需要實現(xiàn)異步事件機制,例如網(wǎng)絡(luò)通訊的收發(fā)

這時就會在C++中回調(diào)java類的方法,于是就會用到j(luò)ava反射機制

在JNI中,實現(xiàn)類反射主要用到以下幾個方法:(本例以反射靜態(tài)方法為例)

JavaVM???????????? jint GetEnv(void **penv, jint version)

JavaVM??????????? ?jint AttachCurrentThread(void **penv, void *args)

JNIEnv???????????? ?jclass FindClass(const char *name)

JNIEnv???????????? ?jmethodID GetStaticMethodID(jclass clazz, const char *name,??const char *sig)

JNIEnv??????????? void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...)

JavaVM???????????jint DetachCurrentThread()

假設(shè)我們要反射的類是:

package com.genius.test;

public class InflectClass {

public static void test(int cmd,String value,String data){

}

}

那么C++中回調(diào)的JNI代碼就是:

void testInflect(int cmd, const char* value, const char* data)

{

if (g_vm == NULL)

{

return ;

}

int status;

JNIEnv *env = NULL;

bool isAttach = false;

status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_4);

if(status != JNI_OK)

{

status = g_vm->AttachCurrentThread(&env, NULL);

if(status < 0) {

return;

}

isAttach = true;

}

jstring valueString = NULL;

jstring dataString = NULL;

jclass inflectClass = NULL;

jmethodID inflectMethod = NULL;

jclass inflectClass = env->FindClass("com/genius/test/InflectClass");

if (inflectClass == NULL)

{

return;

}

jmethodID inflectMethod= env->GetStaticMethodID(inflectClass, "test", "(ILjava/lang/String;Ljava/lang/String;)V");

if (inflectMethod == NULL)

{

return ;

}

valueString = env->NewStringUTF(value);

dataString = env->NewStringUTF(data);

env->CallStaticVoidMethod(inflectClass, inflectMethod, cmd, valueString, dataString);

end:

if (env->ExceptionOccurred())

{

env->ExceptionDescribe();

env->ExceptionClear();

}

if (isAttach)

{

g_vm->DetachCurrentThread();

}

env->DeleteLocalRef(dataString);

}

其中g(shù)_vm是全局的虛擬機實例,可以在

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);

函數(shù)中保存該實例

jint GetEnv(void **penv, jint version)是獲取當(dāng)前線程對應(yīng)的JNI環(huán)境指針

在JNI中,多線程間JNIEnv?是不可以共享的,所以不能全局保存使用

獲取是有可能失敗的,比如當(dāng)前是native線程

何為native線程?即在jni中開啟的線程。

而java線程則是調(diào)用native方法的宿主線程,可以是主線程也可以是子線程

在獲取失敗時,調(diào)用jint AttachCurrentThread(void **penv, void *args)來將當(dāng)前線程附加到虛擬機并獲取JNI環(huán)境指針

之后就是通過

jclass FindClass(const char *name)

GetStaticMethodID(jclass clazz, const char *name,??const char *sig)

void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...)

來獲取類方法并調(diào)用

GetStaticMethodID方法的第三個參數(shù)是函數(shù)簽名

主要是c++中重載函數(shù)的存在使得函數(shù)名不能作為區(qū)別函數(shù)方法的唯一標(biāo)示

這時就需要區(qū)別參數(shù)列表,獲取函數(shù)簽名的命令是javap

具體使用方法大家百度一下就知道了

最后如果有附加當(dāng)前線程到虛擬機的話

需要調(diào)用DetachCurrentThread方法來釋放線程

否則線程不能正常結(jié)束

溫馨提示:

理論上通過上面幾個步驟就可以反射到j(luò)ava層了

但實際操作起來會發(fā)現(xiàn)在native線程里執(zhí)行FindClass的時候會找不到該自定義類(系統(tǒng)類可以)

具體原因不詳,解決方案如下:

在JNI_OnLoad里獲取該類對象并保存一個全局引用

JavaVM *g_vm = NULL;

jclass g_inflectClass = NULL;

jmethodID g_methodID = NULL;

void InitInflectClass(JavaVM* vm)

{

g_vm = vm;

JNIEnv *env = NULL;

int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_4);

if(status != JNI_OK)

{

return ;

}

jclass inflectClass = env->FindClass("com/genius/test/InflectClass");

if (inflectClass == NULL)

{

return ;

}

g_inflectClass = inflectClass;

g_methodID = env->GetStaticMethodID(inflectClass, "test", "(ILjava/lang/String;Ljava/lang/String;)V");

if (g_methodID == NULL)

{

return ;

}

}

直接把函數(shù)方法保存下來也可以

然后在C++回調(diào)的時候直接使用該全局類或函數(shù)方法即可

這樣類就反射出來了

總結(jié)

以上是生活随笔為你收集整理的inflect java_在native线程利用JNI 反射自定义类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。