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