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
, и вам нужно овладеть этим на стороне С++ и передать его в экземпляр класса С++, чтобы получить данные о каждом экземпляре.