我如何从 JNI return vector<vector<float>>?

How can I return vector<vector<float>> from JNI?

我有一个 C++ 函数:

std::vector<std::vector<float>> const &GetVertices() { return m_Vertices; }

我需要通过 JNI return 这个值到 Java。

所以,因为我需要 return vector of vector,我认为我必须使用 jobjectArray,像这样:

extern "C" JNIEXPORT jobjectArray JNICALL
Java_com_google_ar_core_examples_
java_helloar_HelloArActivity_fillListWithData(
    JNIEnv *env,
    jobject /* this */
) 

在Java中,我有这个方法:

public native Object[] fillListWithData();

所以,我的问题是,如何将 vector<vector<float>> 转换为 jobjectArray

我知道有一种方法可以创建 jobjectArray:

jobjectArray verticesArr = env->NewObjectArray(verticesVec.size(), WHAT CLASS SHOULD BE HERE?,NULL);

那我怎么输入值呢?

完全class实施

extern "C" JNIEXPORT jobjectArray JNICALL
Java_com_google_ar_core_examples_java_
helloar_HelloArActivity_fillListWithData(
    JNIEnv *env,
    jobject /* this */
) {
    //verticesVec
    vector<vector<float>> verticesVec = initializer->GetVertices(); // THIS VECTOR I NEED TO CONVERT TO JOBJECTARRAY
    jobjectArray verticesArr = env->NewObjectArray(verticesVec.size(), WHAT CLASS SHOULD BE HERE?,NULL);

    //HOW TO FILL THE ARRAY HERE??

    return verticesArr;
}

取决于您希望如何对 Java 中的数据进行操作,例如添加更多元素?您没有提到这一点,所以答案不能更具体。但也许你想要 "java/util/ArrayList" 的浮动。

以下答案应该能为您指明正确的方向: return a jobjectArray which contains lists of data.

对于其他类型的列表,该代码看起来类似。进行一些网络搜索将提供多种解决方案。

如果速度 (CPU/latency) 和数据量不重要,而不是对 Java 数据结构的所有混乱处理,我通常建议将数据序列化为 JSON 和 return 作为字符串。使用例如JsonCpp 很容易将包含对象的 C++ 数据类型序列化为 JSON,并且在 Java 方面有几个用于反序列化的包(再次网络搜索)和许多 Java 框架来了内置工具。

你必须和java.util.Vector一起玩。这样,您可以对

进行非常简单的映射
(C++ side) vector<vector<float> >  --->  Vector<Vector<Float>> (Java side)

代码本身会有点难看。请记住,使用 JNI 并不是很愉快的体验(由于深奥的语法)。

无论如何,您要做的是在 C++ 端创建所有内容并将其传递回 Java

只是摘录

  vector<vector<float> > vect {
                                 { 1.1, 1.2, 1.3 },
                                 { 2.1, 2.2, 2.3 },
                                 { 3.1, 3.2, 3.3 }
                              };
  ...
  ...

  jclass vectorClass = env->FindClass("java/util/Vector");
  ...

  jclass floatClass = env->FindClass("java/lang/Float");
  ...

  jmethodID mid = env->GetMethodID(vectorClass, "<init>", "()V");
  jmethodID addMethodID = env->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z");

  // Outer vector
  jobject outerVector = env->NewObject(vectorClass, mid);
  ...

  for(vector<float> i : vect) {

    // Inner vector
    jobject innerVector = env->NewObject(vectorClass, mid);

    for(float f : i) {
      jmethodID floatConstructorID = env->GetMethodID(floatClass, "<init>", "(F)V");
      ...

      // Now, we have object created by Float(f)
      jobject floatValue = env->NewObject(floatClass, floatConstructorID, f);
      ...

      env->CallBooleanMethod(innerVector, addMethodID, floatValue);
    }

    env->CallBooleanMethod(outerVector, addMethodID, innerVector);

  }

  env->DeleteLocalRef(vectorClass);
  env->DeleteLocalRef(floatClass);

您可以在此处找到完整的示例代码:

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo045

运行 测试后,您可以看到基于 C++ 的数据已传递给 Java

> make test
/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home/bin/java -Djava.library.path=:./lib -cp target recipeNo045.VectorOfVectors
library: :./lib
[1.1,1.2,1.3]
[2.1,2.2,2.3]
[3.1,3.2,3.3]