如何在 Android NDK 上使用 JNI 在 C 和 Java 之间传递复杂的结构

我在Android应用程序的C代码中有一个复杂的结构,我想在Java方面使用它。我已经用谷歌和stackoverflow做了一些研究,所以我从我的C strucutre创建了java类,但现在如何在Java中获取它。

我已经找到了这些信息,关于在类中制作指针并在C端使用它:

Get the field ID : (*env)->GetFieldID(...)
Get the pointer : (*env)->GetLongField(...)
Set the pointer : (*env)->SetLongField(...)

但我不明白它是如何工作的...

在上面,你可以找到我到目前为止所做的...没有那么多!在C端:

ComplexStructure Java_com_main_MainActivity_listenUDP(JNIEnv* env, jclass clazz)
{
    int i,taille;
    ComplexStructure myStruct;    
    taille = -1;    
    taille = recvfrom(socket, &myStruct, sizeof(ComplexStructure ), 0, &rcvAddr, &sizeOfSock);
    if(taille != -1)
    {   
        return myStruct;
    }
    return NULL;
}

在Java方面:

public void getFromUDP() {

    ComplexClass myClass = new ComplexClass();
    myClass = listenUDP();              
}

@Override
public void run() {
    initUDP();
    getFromUDP();
}


public static native ComplexClass listenUDP();
public static native void initUDP();
public static native void closeUDP();

/** Load jni .so on initialization */
static {
     System.loadLibrary("native-interface");
}

编辑:我想补充一点,我的结构非常复杂,就像这样:

typedef struct{
  TYPE_A myStructA;
  TYPE_B myStructB;
  TYPE_C myStructC;
  TYPE_D myStructD;
}ComplexStructure;

typedef struct{
  float rad;
  int size;
  bool isEmpty;
}TYPE_A;

typedef struct{
  float rad;
  bool isEmpty;
  float color;
  int temp;
}TYPE_B;

typedef struct{
  int temp;
  float rain;
  bool isEmpty;
}TYPE_C;

typedef struct{
  float rad;
  int idPerson;
  bool isOnTime;
}TYPE_D;

更复杂的是,只是一个例子来向您展示它是如何的!


答案 1

您不能将原始的 C 结构传递到 Java 中,并期望它把这些结构视为类。您需要为结构创建一个类。我看到你已经这样做了,所以你唯一需要做的就是把这个结构转换成类的一个实例。

Java 端的代码:

public static native ComplexClass listenUDP();

将转换为:

JNIEXPORT jobject JNICALL Java_com_main_MainActivity_listenUDP(JNIEnv *env, jclass);

在该 C 代码中,您需要使用该函数加载 ComplexClass。然后,要创建该类的新实例(如果您有零参数构造函数,则简化了问题),您需要加载构造函数方法签名并在方法中“调用”它。完整代码:env->FindClass();env->NewObject()

jclass complexClass = env->FindClass("/com/main/ComplexClass");
jmethod constructor = env->GetMethodId(complexClass, "<init>", "()com/main/ComplexClass"); //The name of constructor method is "<init>"
jobject instance = env->NewObject(complexClass, constructor);

然后,您需要使用 设置此类的字段。如果您有更多对象作为字段,并且想要创建它们,则对另一个对象重复上述过程。env->setXXXField();

这看起来非常复杂,但这是在托管Java代码中使用本机C的代价。


答案 2

推荐