Я новичок в 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 ++ ...

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

1
Aleksey Timoshchenko 29 Май 2019 в 19:07

2 ответа

Лучший ответ

В этом случае все довольно просто. Все, что вам нужно сделать, это передать 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/recipes/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
1
Oo.oO 20 Фев 2020 в 21:24

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

0
Siva Rahul 24 Июн 2019 в 06:49