JNI SetFloatArrayElement()不起作用

时间:2016-11-03 18:53:26

标签: java android c++ android-ndk

我尝试修改jfloatArray中的某些值,然后再将其返回到java Android代码。 我发现我无法使用常规方式newArray[i] = result[i];来执行此操作,而应该env->SetFloatArrayElement(newArray,i,result[i]);

问题是此函数抛出错误:

  

[armeabi-v7a]编译++ arm:tensorflow_mnist< = tensorflow_jni.cc   jni /./ tensorflow_jni.cc:函数' _jfloatArray *   Java_jp_narr_tensorflowmnist_DigitDetector_detectDigit(JNIEnv的*   jobject,jintArray)':jni /./ tensorflow_jni.cc:171:14:错误:' JNIEnv'   没有名为' SetFloatArrayElement'            env-> SetFloatArrayElement(newArray,I,导致[I]);                 ^

代码:

JNIEXPORT jfloatArray JNICALL
TENSORFLOW_METHOD(detectDigit)(JNIEnv* env, jobject thiz, jintArray raw_pixels) {

    jboolean iCopied = JNI_FALSE;
    jint* pixels = env->GetIntArrayElements(raw_pixels, &iCopied);
    jfloatArray newArray = env->NewFloatArray(2);
    jfloat *result = process( reinterpret_cast<int*>(pixels) );


    for(int i=0; i<2; ++i) {

        //VLOG(0) <<  " (" << i << "): " << newArray[i];
        //newArray[i] = result[i];
        //env->SetFloatArrayElement(newArray,i,result[i]);
     }


    env->ReleaseIntArrayElements(raw_pixels, pixels, JNI_ABORT);
    env->ReleaseFloatArrayElements(newArray, result, JNI_ABORT);

    free(result);

    return newArray;
}

1 个答案:

答案 0 :(得分:2)

  

我尝试修改jfloatArray中的某些值,然后再将其返回到java Android代码。我发现我无法使用常规方式newArray[i] = result[i];来执行此操作,而应该env->SetFloatArrayElement(newArray,i,result[i]);

是什么让你这么想?当编译器通知您时,JNI没有SetFloatArrayElement()函数。仅Object数组有单个元素设置功能,即SetObjectArrayElement()

处理原始数组有几种选择。

  • 经典机制是使用适当的Get*ArrayElements()函数来获取普通数组,修改数组,然后使用ReleaseArrayElements()。另请注意,使用此方法,如果您要提交更改(就像您一样),则必须使用模式0JNI_COMMIT,而不是JNI_ABORT

  • 对于不会调用其他JNI函数的快速运行用途,您可以考虑使用GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical()。但是,如果在get和release之间进行任何I / O,则不应该这样做。

  • 但是,对于您的具体情况,我建议SetFloatArrayRegion()。有一个相应的GetFloatArrayRegion(),但您不需要它,因为您不关心固定(Java)数组元素的初始值。

使用第三种替代方案可能如下所示:

JNIEXPORT jfloatArray JNICALL
TENSORFLOW_METHOD(detectDigit)(JNIEnv* env, jobject thiz, jintArray raw_pixels) {

    jfloatArray newArray = env->NewFloatArray(2);
    jint* pixels = env->GetIntArrayElements(raw_pixels, NULL);

    jfloat *result = process( reinterpret_cast<int*>(pixels) );

    env->ReleaseIntArrayElements(raw_pixels, pixels, JNI_ABORT);
    env->SetFloatArrayRegion(newArray, 0, 2, result);

    free(result);

    return newArray;
}

如果您可以依赖process()函数快速运行且没有任何阻止的可能性,那么您可以考虑使用GetPrimitiveArrayCritical()ReleasePrimitiveArrayCritical()来访问像素阵列。由于避免制作像素阵列的副本,这可能会更有效,但是您无法确定已使用的方法是否会复制。 (特别注意GetIntArrayElements()的第二个参数是输出变量;它报告是否已复制,但不指示复制。