日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

内构函数java_Android JNI参数传递

發布時間:2023/12/10 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内构函数java_Android JNI参数传递 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java中調用native函數傳遞的參數是Java數據類型,到了JNI層需進行數據類型轉換,基本數據類型是在前面加個j,如int——>jint,應用數據類型除了基本數據類型的數據、Class、String和Throwable外,其余所有Java對象的數據類型在JNI中都用jobject表示。

//Java層com.xxx.yyy包MyJni.java中的jnitest有三個參數

jnitest(String path, String name, MyJni mj);

//JNI層對應的函數的后三個參數與jnitest的參數對應

com_xxx_yyy_MyJni_jnitest(JNIEnv *env, jobject thiz, jstring path, jstring name, jobject mj);

若對象類型都用就object表示,就好比是native層的void* 類型一樣。第二個參數就object代表Java層的實例對象,如果Java層是static函數,則這個參數將是jclass,表示在調用哪個Java Class的靜態函數。

JNIEnv介紹

JNIEnv是一個與線程相關的代表JNI環境的結構體,內部結構如圖:

從上圖可知JNIEnv提供了一些JNI系統函數:

調用Java的函數

操作jobejct對象等很多事情

每個線程都有一個JNIEnv,由于線程相關,所以一個線程不能使用另一個線程的JNIEnv結構體。JNIEnv是native函數轉換成JNI層函數后有虛擬機傳進來的,但當后臺線程收到一個網絡消息,且需有native層函數主動回調Java層函數時,JNIEnv如何傳遞?

這就要用到JavaVM,它是虛擬機在JNI層的代表,如下:

//全進程只有一個JavaVM對象,可保存且在任何地方都可使用

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

而JavaVM 和 JNIEnv的關系如下:

調用JavaVM的AttachCurrentThread函數,就可得到這個線程的JNIEnv結構體,即可在后臺回調Java函數。

在后臺線程退出前,需調用JavaVM的DetachCurrentThread函數釋放對應的資源。

通過JNIEnv操作jobject

Java引用類型除了少數幾個外,其余在JNI層都會用jobject來表示對象的數據類型,操作jobject的本質是操作Java對象的成員變量和成員函數。

jfieldID 和 jmethodID 介紹

JNI規則中用jfieldID 和 jmethodID表示Java類的成員變量和成員函數,可通過JNIEnv的函數得到:

jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);

jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);

其中,jclass表示Java類,name表示成員函數或成員變量的名字,sig為這個函數和變量的簽名信息。使用方法如下:

MyJni(JNIEnv *env, jobject mj)......

{

//先找到com.xxx.yyy.MyJni類在JNI層中對應的jclass實例。

jclass myJniInterface = env->FindClass("com.xxx.yyy.MyJni");

//取出MyJni類中函數jnitest的jMethodID。

mMyJniMethodID = env->GetMethodID(myJniInterface, "jnitest", "(Ljava/lang/String;JJ)V");

//取出MyJni類中函數jnitest1的jMethodID。

mJniTestMethodID = env->GetMethodID(myJniInterface, "jnitest1",

"(Ljava/lang/String;Ljava/lang/String;)V");

如果每次操作jobject前都去查詢jmethodID或jfieldID,將會影響程序的運行效率,故在初始化時可取出ID并保存起來供后續使用。

使用jfieldID 和 jmethodID

實例代碼如下:

virtual bool myjni(const char* path, long long lastModified, long long fileSize)

{

jstring pathstr;

if ((pathStr = mEnv->NewStringUTF(path)) == NULL)

return;

/*

調用JNIEnv的CallVoidMethod函數,注意CallVoidMethod的參數:

第一個是MyJni的jobject對象,

第二個是函數myjni的jmethodID,后面是Java中myjni的參數

*/

mEnv->CallVoidMethod(mClient, mMyJniMethodID, pathStr, lastModified, fileSize);

mEnv->DeleteLocalRef(pathStr);

return (!mEnv->ExceptionCheck());

通過JNIEnv輸出CallVoidMethod,再把jobject、jMethodID和對應的參數傳進去,JNI層就能調用Java對象的函數。

實際上JNIEnv輸出一系列類似CallVoidMethod的函數,形式如下:

NativeType CallMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)

其中type對應Java函數的返回值類型,例如CallIntMethod、CallVoidMethod等。

上面是針對非static函數,如果調用Java的static函數,則用JNIEnv輸出的CallStatic< Type>Method系列函數。

通過jfieldID操作jobject的成員變量,如下:

//獲得filedID可調用GetField系列函數獲取jobject對應的成員變量值

nativeType GetField(JNIEnv *env, jobject obj, jfieldID fieldID)

//或調用SetField系列函數設置jobject對應的成員變量值

void SetField(JNIEnv *env, jobject obj, jfield fieldID, NativeType value)

JNI類型簽名介紹

static JNINativeMethod gMethods[] = {

......

{

"processFile"

"(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V",

(void*)com_xxx_yyy_MyJni

},

......

}

代碼中字符串”(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”是Java中對應函數的簽名信息,有參數類型和返回值類型共同組成。Java支持函數重載,可定義同名但不同參數的函數,進根據函數名無法找到具體函數,故JNI技術中將參數類型和返回值類型作為函數的簽名信息。

JNI規范定義的函數簽名信息格式:

(參數1類型標示參數2類型標示...參數n類型標示)返回值類型標示

“(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”,其中括號內是參數類型的標識,最右邊是返回值類型的標識,void類型對應的標識是V。當參數的類型是引用類型時,其格式是“L包名;”,其中包名中的“.”換成“/”。Ljava/lang/String表示是一個Java的String類型。

總結

以上是生活随笔為你收集整理的内构函数java_Android JNI参数传递的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。