JNI: ассоциация между классами Java и C ++ - PullRequest
1 голос
/ 30 сентября 2019

Поскольку классы 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) действительно странно.

Есть либолее подходящий способ?

...