Поскольку классы C ++ не доступны напрямую из Java, у меня есть оболочка Java с собственными функциями instantiate
(вызывается из конструктора Java) и release
(вызывается из метода Java finalize
).
Это было бы довольно просто, если бы не одно неудобство. Вместо того чтобы хранить один экземпляр C ++, я считаю логичным иметь отдельные экземпляры классов C ++ для каждого экземпляра класса Java. Для этого я сохраняю указатель на экземпляр C ++ в Java-объекте, который хранится как долго.
Вот как это эффективно выглядит:
Java:
class MyClassWrapper {
@Keep private long jniInstance;
MyClassWrapper(int arg1, int arg2, int arg3) {
instantiate(arg1, arg2, arg3);
}
@Override
protected void finalize() {
release();
}
private native void instantiate(int arg1, int arg2, int arg3);
public native void release();
public native int process(short[] data);
}
C ++
void MyClass::process(const short *data) {
. . .
}
MyClass* MyClass::fromJava(JNIEnv *env, jobject obj) {
return obj == nullptr ? nullptr
: (MyClass *) env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "jniInstance", "J"));
//============================================================
extern "C" JNIEXPORT JNICALL void
Java_myapp_mypackage_MyClassWrapper_instantiate(JNIEnv *env, jobject thiz, jint arg1, jint arg2, jint arg3) {
env->SetLongField(thiz,
env->GetFieldID(env->GetObjectClass(thiz), "jniInstance", "J"),
(jlong)new MyClass(arg1, arg2, arg3) );
}
extern "C" JNIEXPORT void JNICALL
Java_myapp_mypackage_MyClassWrapper_release(JNIEnv *env, jobject thiz) {
jfieldID fldId = env->GetFieldID(env->GetObjectClass(thiz), "jniInstance", "J");
MyClass *instance = (MyClass *) env->GetLongField(thiz, fldId);
if (instance != nullptr) {
delete instance;
env->SetLongField(thiz, fldId, (jlong) nullptr);
}
}
extern "C" JNIEXPORT jobject JNICALL
Java_myapp_mypackage_MyClassWrapper_process(
JNIEnv *env, jobject thiz, jshortArray jdata) {
jshort *data = env->GetShortArrayElements(jdata, nullptr);
MyClass *instance = MyClass::fromJava(env, thiz);
instance->process(data);
env->ReleaseShortArrayElements(jboard, data, JNI_ABORT);
}
Работает нормально. Однако преобразование ссылки в длинный и длинный назад в ссылку выглядит для меня немного неловко, хотя использование long
с 32-разрядным процессором (большинство телефонов на базе Android) действительно странно.
Есть либолее подходящий способ?