【问题标题】:JNI SetFloatArrayElement() not workingJNI SetFloatArrayElement() 不工作
【发布时间】:2016-11-03 18:53:26
【问题描述】:

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

问题是这个函数抛出错误:

[armeabi-v7a] 编译++ arm : tensorflow_mnist SetFloatArrayElement(newArray,i,result[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;
}

【问题讨论】:

    标签: java android c++ android-ndk


    【解决方案1】:

    我正在尝试修改 jfloatArray 中的一些值,然后再将其返回给 java Android 代码。我发现我不能使用常规方式 newArray[i] = result[i]; 来执行此操作,而应该使用 env-&gt;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() 的第二个参数是一个输出 变量;它报告是否已经制作了一个副本,但并不指示它)。

    【讨论】:

    • 我实际上在 Unity3D 的 JNI 参考中找到了 SetFloatArrayElement()。 docs.unity3d.com/ScriptReference/… 不过,谢谢。我现在改用 SetFloatArrayRegion()。
    • @BernardoGO,显然,AndroidJNI 没有将 1:1 映射到 JNI。我知道这可能会让人感到意外。 FWIW,JNI 的规范参考是 the one provided by Oracle
    • 哦,我明白了。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多