JNI - как использовать несколько экземпляров оболочки Jni с разными полями?

фон

У меня есть проект Android, который использует JNI (используя NDK) для кодирования на Java и C/C++.

Я создал java-упаковщик на стороне java, который будет выполнять все операции Jni сам по себе, в то время как никакой другой java-класс не может получить доступ к операциям jni напрямую, кроме этой оболочки.

эта проблема

проблема в том, что я хочу создать несколько экземпляров этой оболочки, в то время как часть Jni должна иметь экземпляр для каждой оболочки Jni.

это проблема, так как часть Jni содержит одинаковые поля для всех экземпляров.

вопрос

Как я могу решить эту проблему, чтобы для каждого экземпляра java-обертки java был экземпляр в части jni?

Я думал, может быть, я мог бы поместить все поля в класс C++, и иметь функцию init(), которая будет возвращать новый экземпляр этого для CTOR JniWrapper, и с тех пор, для каждой функции JNI, которая нуждается в полях, он получит этот класс в качестве параметра. возможно, это может быть указатель, как показано на этой ссылке.

к сожалению, я понятия не имею, как это сделать.

Может кто-нибудь, пожалуйста, помогите?

образец

Вот пример кода, который, я надеюсь, прояснит ситуацию для тех, кто не понимает проблему:

Java часть:

public class JniWrapper
  {
  static
    {
    System.loadLibrary("JniTest");
    }

  private native void foo(Bitmap bitmap);
  }

JNI часть:

...
// sadly, all of those fields are actually a global fields
int _intField;
float _floatField;    
//those are just sample fields. i would also like to store pointers and objects...

JNIEXPORT void JNICALL ...foo(JNIEnv * env, jobject obj, jobject bitmap)
  {
  // do something with the fields, as if they all belong to the JniWrapper, 
  // and no other instances of JniWrapper are allowed to change them
  }

2 ответа

Решение

Я нашел возможное решение (ссылка здесь), чтобы использовать jlong ​​или jobject, чтобы быть дескриптором (или указателем, если хотите) объекта, который был создан на стороне JNI.

люди говорили, что для лучшей совместимости лучше использовать задание в качестве ByteBuffer вместо jlong.

решение:

Java сторона:

private native ByteBuffer init();
private native void foo(ByteBuffer handle);

Сторона JNI:

/**a class to hold the fields*/
class FieldsHolder
  {
  ... //private fields, for each instance
  }

создание объекта JNI и отправка на сторону java:

JNIEXPORT jobject JNICALL ...init(JNIEnv * env, jobject obj)
  {
  FieldsHolder* myClass= new FieldsHolder();
  ... //prepare fields of the class
  return env->NewDirectByteBuffer(myClass, 0);
  }

повторное использование объекта JNI:

JNIEXPORT void JNICALL ...foo(JNIEnv * env, jobject obj, jobject handle)
  {
  FieldsHolder* myClass= (FieldsHolder*) env->GetDirectBufferAddress(handle);
  //now we can access the fields again.
  }

У вас должны быть классы C++ на стороне JNI, и вам нужно связать экземпляр класса C++ с каждым экземпляром вашего класса-оболочки JNI. Вам нужно будет добавить нативные методы new а также delete экземпляры класса C++, и вам потребуется пуленепробиваемый способ обеспечения того, чтобы delete-calling метод вызывается каждый раз, когда выпускается экземпляр вашего класса-оболочки JNI, например, через close() метод, finally{} блоки, или даже finalize() Метод: это один из случаев, когда его использование является законным. Вам нужно хранить указатель на экземпляр C++ в каждом экземпляре Java, например, как Java longи вам нужно получить это на стороне C++ и привести его к экземпляру класса C++, чтобы получить данные для каждого экземпляра.

Другие вопросы по тегам