Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a complex structure between C and Java with JNI on Android NDK

I have a complex strucutre in the C code on my Android application and I would like to use it in the Java side. I've done some research with google and in stackoverflow, so I've created the java class from my C strucutre, but now how to get it in Java.

I've found these informations, about making a pointer in the class and use this on the C side :

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

But I don't understand how it really works ...

Above, you can find what I've done until now ... not so much ! On the C side :

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;
}

And on the Java side :

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");
}

EDIT : I want to add that my structure is very complex like that :

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;

Even more complex, just an example to show you how it is !

like image 935
Bibu Avatar asked Apr 24 '12 14:04

Bibu


People also ask

How do I return a structure in JNI?

1) create the object in Java and pass it to the native method. This then sets the fields. 2) create the object in the native method. Check JNI 1.1 Specification, especially JNI Functions.

What is Jclass in JNI?

typedef jobject jclass; In C++, JNI introduces a set of dummy classes to enforce the subtyping relationship. For example: class _jobject {}; class _jclass : public _jobject {}; ...

What is NDK and JNI?

JNI is just the way that Java handles calling into native/C++ code, and calling back into Java from there. It has nothing to say about Android - it is a Java language feature. The Android NDK is a way to write Android applications using code called by JNI.

How does an Android APK execute compiled native code using the Java native interface?

Using Android Studio 2.2 and higher, you can use the NDK to compile C and C++ code into a native library and package it into your APK using Gradle, the IDE's integrated build system. Your Java code can then call functions in your native library through the Java Native Interface (JNI) framework.


1 Answers

You cannot pass raw C structs into Java and expect it to treat these structs as classes. You need to create a class for your struct. I see you already did that, so the only thing you need to do is to convert this struct into an instance of the class.

The code on the Java side:

public static native ComplexClass listenUDP();

will translate to:

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

In that C code, you need to load the ComplexClass using the env->FindClass(); function. Then to create a new instance of that class (it simplifies matters if you have zero-parameter constructor), you need to load a constructor method signature and "invoke" it in the env->NewObject() method. Full code:

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);

Then you need to set the fields of this class using env->setXXXField();. If you have more objects as fields and want to alse create them, then repeat the above process for another object.

This looks very complicated, but that's the price for using native C in managed Java code.

like image 115
Jakub Zaverka Avatar answered Sep 20 '22 09:09

Jakub Zaverka