2017-09-04 2 views
0

Je suis novice en programmation jni. Je voudrais passer un tableau float de java à jni, allouer dynamiquement de la mémoire suffisante pour faire flotter un tableau dans jni side, stocker des valeurs dans jfloatArray, et y accéder dans java. Je ne veux pas retourner le jfloatArray, juste modifier le tableau float d'entrée passé. J'ai essayé la méthode ci-dessous, mais elle ne modifie pas mon tableau float java. Comment y parvenir?Programmation JNI

Java Code: 

    float[] pointList = null; 
    outputBitmap = callJNIFunc(pointList, inputBitmap); 

JNI Code: 

Bitmap callJNIFunc(JNIEnv *env, jfloatArray pointListInPixels, jobject inputBitmap) { 
    pointListInPixels = (env)->NewFloatArray(pointListSize.M * 2); 
    env->SetFloatArrayRegion(pointListInPixels, 0, pointListSize.M * 2, pointFloats); 
} 

Je lis de pass data between Java and C que cela peut être réalisé en faisant passer un objet personnalisé. Cependant, je ne suis pas tout à fait sûr comment faire de JNI pour un objet java contenant tableau flottant comme celui-ci

public class CustomObject{ 
    public float[] points; 
    public float[] getPoints() { 
    return points; 
    } 

    public void setPoints(float[] points) { 
    this.points = points; 
    } 

} 

Répondre

0

Regardez la première ligne de votre fonction JNI.

Initialement, pointListInPixels représente l'adresse d'un objet Java - le float[] pointList dans votre code Java.

Dans la ligne suivante, vous l'attribuez à (env)->NewFloatArray, ce qui signifie que pointListInPixels ne pointe plus vers votre float[] pointList en Java, mais vers un nouveau tableau. Par conséquent, votre appel au SetFloatArrayRegion n'a aucun effet. Il modifie un tableau dans Java, bien sûr, mais il ne modifie pas le tableau que vous voulez qu'il modifie.

La méthode correcte de le faire est de rendre votre fonction JNI retourner un jFloatArray, la conversion de votre code Java:

float[] pointList = callJNIFunc(); 

et votre code JNI à:

jFloatArray pointListInPixels = (env)->NewFloatArray(pointListSize.M * 2); 
    env->SetFloatArrayRegion(pointListInPixels, 0, pointListSize.M * 2, pointFloats); 
    return pointListInPixels; 

signatures de méthode doivent être changé au besoin.

+0

Mais mon jni func a déjà un type de retour différent. Je ne peux pas retourner ça. C'est le problème principal. Je voudrais le prendre comme référence et modifier @konsolas –

+0

@rsd_unleashed Java est la valeur de passage, y compris JNI. Tu ne peux pas faire ça. – EJP

+0

Vous pouvez renvoyer un objet avec deux champs de JNI. Ou utilisez deux fonctions JNI pour les deux objets. – konsolas

0

Vous pouvez créer conteneur classe pour la valeur de retour comme ceci:

public class Result{ 
    public final Bitmap bitmap; 
    public final float[] pointListInPixels; 

    public Result(Bitmap bitmap, float[] pointListInPixels){ 
     this.bitmap = bitmap; 
     this.pointListInPixels = pointListInPixels; 
    } 
} 

construction et retour objet Result de JNI:

Result callJNIFunc(JNIEnv *env, jfloatArray pointListInPixels, jobject inputBitmap) { 
    // load class by name 
    jclass cls = env->FindClass("my/package/name/Result"); 
    if (env->ExceptionOccurred()) return NULL; 

    // take constructor by signature 
    jmethodID constructorId = env->GetMethodID(cls, "<init>", "(android/graphics/Bitmap, [[F)V"); 
    if (env->ExceptionOccurred()) return NULL; 

    jobject output_bitmap; // create bitmap and implement logic 

    pointListInPixels = (env)->NewFloatArray(pointListSize.M * 2); 
    env->SetFloatArrayRegion(pointListInPixels, 0, pointListSize.M * 2, pointFloats); 

    // create result object 
    jobject result = env->NewObject(cls, constructorId, output_bitmap, pointListInPixels); 

    return result; 
} 

Pour cet exemple de code que vous ne avez pas besoin de delete objets car ils sont créés par java api (à l'intérieur de java tas). Vous pouvez utiliser simple meta loader pour les objets Java à partir de ce code snippet