成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Android Studio NDK開發(fā)-JNI調(diào)用Java函數(shù)

luzhuqun / 1037人閱讀

摘要:使用可以獲取類的方法得到例如如果調(diào)用的是靜態(tài)方法需要使用獲取。那么方法簽名的規(guī)則又是怎么樣呢方法簽名在中第四個(gè)參數(shù)就是方法簽名,是支持重載的,所以需要標(biāo)明方法的傳參和返回值,這就是方法的簽名。其中代表不傳參數(shù),代表返回值為。

相對(duì)于NDK來說SDK里面有更多API可以調(diào)用,有時(shí)候我們在做NDK開發(fā)的時(shí)候,需要在JNI直接Java中的方法和變量,比如callback,系統(tǒng)信息等....
如何在JNI中調(diào)用Java方法呢?就需要先了解FindClassGetMethodID了。

FindClass和GetMethodID

在JNI中可以通過FindClass可以找到Java類,得到jclass,例如:

jclass clz=(*env)->FindClass(env,"com/jjz/JniHandle");

FindClass的第二個(gè)參數(shù)需要傳入類的完整包名。

使用GetMethodID可以獲取類的方法,得到j(luò)methodID,例如:

jmethodID getStringFromJava=(*env)->GetMethodID(env,class,"getStringForJava","()V");

如果調(diào)用的是靜態(tài)方法需要使用GetStaticMethodID獲取。通過FindeClass可以在JNI中找到需要調(diào)用的類,GetMethodID可以找到對(duì)應(yīng)的方法,這樣就可以在JNI中調(diào)用Java的方法了。
在GetMethodID中,第四個(gè)參數(shù)是()V,這個(gè)是方法簽名。那么方法簽名的規(guī)則又是怎么樣呢?

方法簽名

GetMethodID中第四個(gè)參數(shù)()V就是方法簽名,Java是支持重載的,所以需要標(biāo)明方法的傳參和返回值,這就是方法的簽名。它是用來保證方法的唯一性。其中()代表不傳參數(shù),V代表返回值為void
方法簽名對(duì)于Java的類型都有一一對(duì)應(yīng)的值。方法簽名中用大寫的字母對(duì)應(yīng)了java的基本數(shù)據(jù)類型:

Z -> boolean

B -> byte

C -> char

S -> short

I -> int

J -> long

F -> float

D -> double

其實(shí)就是有兩個(gè)比較特殊的:boolean對(duì)應(yīng)的是Z,long對(duì)應(yīng)的J,其他的都是首個(gè)字母的大寫即可。

數(shù)組的表示方法,以[為標(biāo)志,一個(gè)[標(biāo)識(shí)一維數(shù)組,[[表示二維數(shù)組,例如:

byte[] -> [B

int[][] -> [[I

引用類型的表示方法,需要以L開頭,以;結(jié)束,中間對(duì)應(yīng)類型的包名加類名,例如:

String -> Ljava/lang/String;

Object -> Ljava/lang/Object;

自定義類的表示方法,比如包名為jjz.example,類名為JniHandle的表示方法:

jjz.example.JniHandle ->Ljjz/example/JniHandle;

除了手動(dòng)輸入類名和方法簽名以外,JDK還提供了直接生成方法簽名的工具javap。
build之后可以在路徑../app/build/intermediates/classes/debug下可以找到build之后生成的.class文件,運(yùn)行命令:

javap -s com/jjz/JniHandle

就可以得到這個(gè)類的所有的方法簽名:

Compiled from "JniHandle.java"
public class com.jjz.JniHandle {
? public com.jjz.JniHandle();
? ? descriptor: ()V

? public static java.lang.String getStringFromStatic();
? ? descriptor: ()Ljava/lang/String;

? public java.lang.String getStringForJava();
? ? descriptor: ()Ljava/lang/String;
}

有了類的引用,和方法的簽名就可以直接在JNI中調(diào)用Java方法了,下面分別介紹下靜態(tài)方法和類方法的調(diào)用。

靜態(tài)方法的調(diào)用

調(diào)用類的靜態(tài)方法,首先要得到類的引用,再調(diào)用類的靜態(tài)方法。
先定義一個(gè)類和靜態(tài)方法用來提供給JNI調(diào)用:

public class JniHandle {

? ? public static String getStringFromStatic() {
? ? ? ? return "string from static method in java";
? ? }
}

在定義了一個(gè)native方法com.jjz.NativeUtil.callJavaStaticMethodFromJni,生成這個(gè)方法的JNI代碼,在JNI代碼中調(diào)用JniHandle類的靜態(tài)方法:

JNIEXPORT void JNICALL
Java_com_jjz_NativeUtil_callJavaStaticMethodFromJni(JNIEnv *env, jclass type) {

? ? jclass jniHandle = (*env)->FindClass(env, "com/jjz/JniHandle");
? ? if (NULL == jniHandle) {
? ? ? ? LOGW("can"t find JniHandle");
? ? ? ? return;
? ? }
? ? jmethodID getStringFromStatic = (*env)->GetStaticMethodID(env, jniHandle, "getStringFromStatic",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "()Ljava/lang/String;");
? ? if (NULL == getStringFromStatic) {
? ? ? ? (*env)->DeleteLocalRef(env, jniHandle);
? ? ? ? LOGW("can"t find method getStringFromStatic from JniHandle ");
? ? ? ? return;
? ? }
? ? jstring result = (*env)->CallStaticObjectMethod(env, jniHandle, getStringFromStatic);
? ? const char *resultChar = (*env)->GetStringUTFChars(env, result, NULL);
? ? (*env)->DeleteLocalRef(env, jniHandle);
? ? (*env)->DeleteLocalRef(env, result);
? ? LOGW(resultChar);

}

在Java中調(diào)用com.jjz.NativeUtil.callJavaStaticMethodFromJni可以該方法可以在logcat中看到string from static method in java,這樣就完成了在JNI中調(diào)用了Java靜態(tài)方法。

類方法的調(diào)用

調(diào)用類方法要更加的復(fù)雜一些,調(diào)用步驟:

通過findClass找到類

通過GetMethodID得到構(gòu)造函數(shù)

通過調(diào)用構(gòu)造函數(shù)得到一個(gè)類的實(shí)例

通過GetMethodID得到需要調(diào)用的方法

使用類的實(shí)例調(diào)用方法

先定義一個(gè)類方法:

public class JniHandle {
? ? public String getStringForJava() {
? ? ? ? return "string from method in java";
? ? }
}

再定義一個(gè)native方法:com.jjz.NativeUtil.callJavaMethodFromJni,生成該方法的JNI代碼,在JMI代碼中實(shí)現(xiàn)調(diào)用JniHandle的類方法getStringForJava,代碼如下:

JNIEXPORT void JNICALL
Java_com_jjz_NativeUtil_callJavaMethodFromJni(JNIEnv *env, jclass type) {

? ? jclass jniHandle = (*env)->FindClass(env, "com/jjz/JniHandle");
? ? if (NULL == jniHandle) {
? ? ? ? LOGW("can"t find jniHandle");
? ? ? ? return;
? ? }
? ? jmethodID constructor = (*env)->GetMethodID(env, jniHandle, "", "()V");
? ? if (NULL == constructor) {
? ? ? ? LOGW("can"t constructor JniHandle");
? ? ? ? return;
? ? }
? ? jobject jniHandleObject = (*env)->NewObject(env, jniHandle, constructor);
? ? if (NULL == jniHandleObject) {
? ? ? ? LOGW("can"t new JniHandle");
? ? ? ? return;
? ? }
? ? jmethodID getStringForJava = (*env)->GetMethodID(env, jniHandle, "getStringForJava",
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "()Ljava/lang/String;");
? ? if (NULL == getStringForJava) {
? ? ? ? LOGW("can"t find method of getStringForJava");
? ? ? ? (*env)->DeleteLocalRef(env, jniHandle);
? ? ? ? (*env)->DeleteLocalRef(env, jniHandleObject);
? ? ? ? return;
? ? }
? ? jstring result = (*env)->CallObjectMethod(env, jniHandleObject, getStringForJava);
? ? const char *resultChar = (*env)->GetStringUTFChars(env, result, NULL);
? ? (*env)->DeleteLocalRef(env, jniHandle);
? ? (*env)->DeleteLocalRef(env, jniHandleObject);
? ? (*env)->DeleteLocalRef(env, result);
? ? LOGW(resultChar);

}

調(diào)用方法com.jjz.NativeUtil.callJavaMethodFromJni即可看到Java中的字符串傳遞給了JNI最后輸出到了Logcat上。

在上面的代碼中有一個(gè)方法叫做DeleteLocalRef,它的意思是釋放局部引用,Android VM釋放局部引用有兩種方法:

本地方法執(zhí)行完畢之后VM自動(dòng)釋放

通過調(diào)用DeleteLocalRef手動(dòng)釋放

既然上面說了VM會(huì)自動(dòng)釋放引用為什么還需要手動(dòng)釋放呢?
其實(shí)某些局部變量會(huì)阻止它所引用的對(duì)象被GC回收,它所引用的對(duì)象無法被GC回收,自己本身也就無法被自動(dòng)釋放,因此需要使用DeleteLocalRef。而這里使用了JNI Local Reference,在JNI中引用了Java對(duì)象,如果不使用DeleteLocalRef釋放的話,引用無法回收,就會(huì)造成內(nèi)存泄露。

源代碼地址:https://github.com/jjz/androi...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64844.html

相關(guān)文章

  • Andorid Studio NDK開發(fā)-Hello World

    摘要:介紹了在中配置的開發(fā)環(huán)境開發(fā)環(huán)境配置,開發(fā)環(huán)境配置完成之后,就要寫一下著名的程序了。尤其是但是并不妨礙你使用其他語言,只要調(diào)用約定支持就可以了。是指定所在的目錄,項(xiàng)目成功之后,會(huì)在目錄里生成文件。是包名加上類名。 介紹了在Android Studio中配置NDK的開發(fā)環(huán)境:Android Studio NDK開發(fā)-環(huán)境配置,NDK開發(fā)環(huán)境配置完成之后,就要寫一下著名的Hello Wor...

    melody_lql 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<