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

фон

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

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

проблема

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

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

вопрос

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

Я думал, может быть, я мог бы поместить все поля в класс С++ и иметь функцию 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
  }

Ответ 1

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

люди сказали, что лучше использовать для работы в качестве ByterBuffer вместо jlong ​​более подходящую работу, чем для jQuer.

решение:

Сторона 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.
  }

Ответ 2

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