Android NDK - JNI 傳遞自定義類型及其數(shù)組傳遞

在實(shí)際開(kāi)發(fā)中,JNI與java有很多場(chǎng)景需要傳遞數(shù)據(jù),有時(shí)是基本數(shù)據(jù)類型,而有時(shí)則是自定義類型。在遇到通過(guò)回調(diào)Java中函數(shù)進(jìn)行自定義類型傳遞時(shí),是不可以直接傳遞,需要進(jìn)行轉(zhuǎn)換,本篇將針對(duì)參數(shù)存在自定義類型和自定義類型數(shù)組兩種場(chǎng)景進(jìn)行舉例說(shuō)明。

基本數(shù)據(jù)類型參數(shù)數(shù)組

針對(duì)如下代碼片段說(shuō)明:

//基本數(shù)據(jù)類型參數(shù)數(shù)組的靜態(tài)函數(shù)
package com.test.jni;
//Java 函數(shù)
public class TestFunc{
    public static void testFunc(float vals[]){
        //...
    }
}

//JNI函數(shù)回調(diào)片段
jclass clz = jenv->FindClass("com/test/jni/TestFunc");
jmethodID methodId = env->GetMethodID(clz,"TestFunc","([F)V");
float[] data = new float[]{1.f,2.f};
//!!錯(cuò)誤示例!!
env->CallStaticVoidMethod(clz,methodId,data);
//正確用例
jfloatArray array = env->NewFloatArray(2);
//參數(shù)1:待賦值數(shù)組;參數(shù)2:賦值起始位置;參數(shù)3:賦值長(zhǎng)度;參數(shù)4:數(shù)據(jù)源
env->SetFloatArrayRegion(array,0,3,data);
env->CallStaticVoidMethod(clz,methodId,array);

自定義結(jié)構(gòu)類型參數(shù)數(shù)組

針對(duì)如下代碼片段說(shuō)明:

//自定義類型
package com.test.jni;
public class MyObject{
    private String name;
    private int number;
    //some getters and setters
    ...
    public MyObject(String name, int number){
        this.name = name;
        this.number = number;
    }
}

//自定義類型參數(shù)數(shù)組的靜態(tài)函數(shù)
package com.test.jni;
//Java 函數(shù)
public class TestFunc{
    public static void testFunc(MyObject vals[]){
        //...
    }
}

//JNI函數(shù)回調(diào)片段
jclass clz = jenv->FindClass("com/test/jni/TestFunc");
jmethodID methodId = jenv->GetMethodID(clz,"TestFunc","([Lcom/test/jni/MyObject;)V");
MyObject myObjects = new MyObject[2];
for(int i = 0; i < myObjects.length; i++){
    myObjects[i] = new MyObject("name_" + i, i);
}
//!!錯(cuò)誤示例!!
jenv->CallStaticVoidMethod(clz,methodId,myObjects);
//正確用例: 需要在JNI層創(chuàng)建類型數(shù)組
jclass jclzMyObject = jenv->FindClass("com/test/jni/MyObject");
jmethodID jmethodConstructID = jenv->GetMethodID(jclzMyObject, "<init>", "()V");
//進(jìn)行實(shí)例創(chuàng)建
jobjectArray array = jenv->NewObjectArray(myObjects.length, jclzMyObject,NULL);
for(int i = 0; i < 2; i++){
    jobject jobjMyObj = jenv->NewObject(jclzMyObject, jmethodConstructID);
    jfieldID nameField = jenv->GetFieldID(jclzMyObject, "name","Ljava/lang/String;");
    jfieldID numberField = jenv->GetFieldID(jclzMyObject,, "number","I");
    jenv->SetObjectField(jobjMyObj, nameField, myObjects[i].name);
    jenv->SetIntField(jobjMyObj, numberField, myObjects[i].number);
    jenv->SetObjectArrayElement(array, i, jobjMyObj);
    jenv->DeleteLocalRef(jobjMyObj);
}

//調(diào)用類的靜態(tài)方法
jenv->CallStaticVoidMethod(clz,methodId,array);

通過(guò)在JNI層重新創(chuàng)建實(shí)例的數(shù)組,并將數(shù)組進(jìn)行賦值,此時(shí)可以通過(guò)該反射調(diào)用Java函數(shù)的方式將JNI層的數(shù)值傳遞到Java層進(jìn)行后續(xù)的計(jì)算處理。有以下需要注意的地方:

  • 在JNI層創(chuàng)建實(shí)例對(duì)象時(shí),需要對(duì)Java層該類的構(gòu)造函數(shù)進(jìn)行有針對(duì)性的實(shí)現(xiàn);
  • 在JNI層創(chuàng)建實(shí)例對(duì)象之后,尤其是還需要加入其數(shù)組數(shù)據(jù)結(jié)構(gòu)中,需要在最后進(jìn)行本地引用的釋放,否則在循環(huán)創(chuàng)建超過(guò)512個(gè)引用之后則會(huì)溢出;
  • 針對(duì)非靜態(tài)方法,則需要類似地通過(guò)反射在JNI層創(chuàng)建類的實(shí)例,通過(guò)調(diào)用實(shí)例函數(shù)方式;

CSDN 同步發(fā)布 地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,881評(píng)論 25 709
  • _ 聲明: 對(duì)原文格式以及內(nèi)容做了細(xì)微的修改和美化, 主要為了方便閱讀和理解 _ 一. 基礎(chǔ) Java Nativ...
    元亨利貞o閱讀 6,086評(píng)論 0 34
  • Android跨進(jìn)程通信IPC整體內(nèi)容如下 1、Android跨進(jìn)程通信IPC之1——Linux基礎(chǔ)2、Andro...
    隔壁老李頭閱讀 11,771評(píng)論 1 46
  • 學(xué)校有個(gè)不認(rèn)識(shí)的老師需要輸血,恰好是我的血型。明天要實(shí)習(xí),后天有考試,猶豫了一下還是撥通了家屬的電話,被告知已經(jīng)有...
    半島鐵臂阿凡達(dá)閱讀 242評(píng)論 2 1
  • 一定要善待自己,讓自己變的更好。又是一場(chǎng)感冒,很難過(guò)!就不能把自己照顧好嗎?總覺(jué)得自己生活挺有規(guī)律的,其實(shí)...
    阿勇的故事閱讀 321評(píng)論 1 0

友情鏈接更多精彩內(nèi)容