Как передать List из Java в JNI C ++ как вектор по ref? - PullRequest
1 голос
/ 29 мая 2019

Я новичок в C ++ и JNI

Поток должен быть таким

Из Java я передаю пустой List в JNI, метод вызова JNI loadData(std::vector<int>) из MyClass и этот метод заполняет мой список данными.

Итак, вопрос

У меня есть

class MyClass {
public:
MyClass();
~MyClass();

void loadData(std::vector<int> & vector);
};


void MyClass::loadData(std::vector<int> & vector)
{
const int size = 10;

vector.resize(size);

for (int i = 0; i < size; ++i) {
    vector.push_back(4);
}
}

Это мой метод, который я написал на чистом C ++, и теперь мне нужно использовать его с Java следующим образом

public native void fillListWithData(List<Integer> list);

Итак, я написал такой метод в JNI, чтобы связать их

extern "C" JNIEXPORT void JNICALL
Java_com_google_ar_core_examples_java
_helloar_HelloArActivity_fillListWithData(
    JNIEnv *env,
    jobject /* this */,
    jobject input
) {
myClass->loadData("HERE I NEED TO PASS MY " input);
}

А вот как мне следует вызвать этот метод

public void TEST(){
    List<Integer> list = new ArrayList<>();
    fillListWithData(list);
    Log.e("TAG", "HERE I NEED TO HAVE A LIST WITH FILLED DATA");
}

Я не могу понять, как JNI передает этот список по ссылке в C ++ ...

Любые идеи ценят

Ответы [ 2 ]

1 голос
/ 31 мая 2019

В этом случае все довольно просто.Все, что вам нужно сделать, это передать List в ваш собственный код и заполнить его внутри JNI части, используя JNI методы доступа на основе

#include <vector>
#include "jni.h"
#include "recipeNo046_FillTheList.h"
using namespace std;

JNIEXPORT void JNICALL Java_recipeNo046_FillTheList_fillTheList
  (JNIEnv *env, jclass cls, jobject obj) {

  vector<int> vect { 1, 2, 3 };

  jclass listClass = env->FindClass("java/util/List");
  if(listClass == NULL) {
    return;                  // alternatively, throw exception (recipeNo019)
  }

  jclass integerClass = env->FindClass("java/lang/Integer");
  if(integerClass == NULL) {
    return;                  // alternatively, throw exception (recipeNo019)
  }

  jmethodID addMethodID = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
  if(addMethodID == NULL) {
    return;                  //                 - || -
  }

  jmethodID integerConstructorID = env->GetMethodID(integerClass, "<init>", "(I)V");
  if(integerConstructorID == NULL) {
    return;                  //                 - || -
  }

  for(int i : vect) {
    // Now, we have object created by Integer(i)
    jobject integerValue = env->NewObject(integerClass, integerConstructorID, i);
    if(integerValue == NULL) {
      return;
    }
    env->CallBooleanMethod(obj, addMethodID, integerValue);
  }

  env->DeleteLocalRef(listClass);
  env->DeleteLocalRef(integerClass);

}

Обратите внимание, что вам не нужно создавать List объект внутри JNI, как он у вас уже есть - внутри C++ кода.Передается как аргумент метода native.

Полный пример кода можно найти здесь:

https://github.com/mkowsiak/jnicookbook/tree/master/recipeNo046

После запуска кода вы можете увидеть данныес C++ передается через объект List.

> make test
/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home/bin/java -Djava.library.path=:./lib -cp target recipeNo046.FillTheList
library: :./lib
1
2
3
0 голосов
/ 24 июня 2019

Ответ, упомянутый @ Oo.oO, может показаться работающим в Windows 10, но не в случае с Windows 8.
Windows 8 не поддерживает работу с контейнерами из библиотек Cpp.
Сообщенная ошибка будет: «% 1 не является допустимым приложением Win32»
Это происходит во время работы Java-программы.
Файл DLL, созданный здесь, кажется, проблема.

...