gpt4 book ai didi

java - JNI中如何实现观察者模式

转载 作者:搜寻专家 更新时间:2023-11-01 01:52:50 31 4
gpt4 key购买 nike

我最近不得不用 Java 外观包装一个 C/C++ 库。其中一个方法接受一个函数作为参数。这基本上是观察者(又名监听器)模式:

void setLogFunction(const std::function<void(std::string&, std::string&)> &callback)
{
_callback = callback;
}

在 Java 方面,您不能传递函数,但可以使用 log() 方法传递对象。

interface Observer {
public void log(String prefix, String message);
}

class MyLibrary {
public MyLibrary() {
initCpp();
}
public native void initCpp();
...
public native void setObserver(Observer observer);
}

如何在 JNI 中实现 setObserver()?

最佳答案

我花了很长时间才实现这个解决方案。我不得不从整个互联网上获取信息。在这里:

//Optional, this is just so that I can retrieve the C++ MyLibrary instance
//easily from the Java.
JNIEXPORT void JNICALL Java_MyLibrary_initCpp(JNIEnv* env, jobject javaMyLibrary) {
//Save the C++ version of MyLibrary as a field inside the Java MyLibrary.
MyLibrary * lib = new MyLibrary();
env->SetLongField(javaMyLibrary, CPP_MYLIBRARY_POINTER_FIELD, ptr_to_jlong(lib));
}

JNIEXPORT void JNICALL Java_MyLibrary_setObserver(JNIEnv* env,
jobject javaMyLibrary, jobject javaObserver) {
//Retrieve the CPP version of MyLibrary. For me, I stored it inside the java
//object as a field, but you can implement it any way you want.
MyLibrary* cppMyLibrary = (MyLibrary*)jlong_to_ptr(
env->GetLongField(javaMyLibrary, CPP_MYLIBRARY_POINTER_FIELD));
if (cppMyLibrary == NULL) {
//Handle the problem
return;
}
jthrowable exc = NULL;

//Keep the jvm object around; the env is not available in another thread
//but can be obtained from the jvm.
JavaVM* jvm;
env->GetJavaVM(&jvm);

//The observer has to be made global; it's not available in another thread.
jobject observer = env->NewGlobalRef(javaObserver);
//TODO: retrieve the previous observer and clean it up with DeleteGlobalRef()
//TODO: clean up this observer when destroying MyLibrary with DeleteGlobalRef()

try {
//At this point, both "jvm" and "observer" are accessible from the other thread.
cppMyLibrary->setLogFunction([jvm, observer] (std::string& p0, std::string& p1) {
JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL); //Obtain the env
jclass clazz = env->GetObjectClass(observer);
jmethodID meth = env->GetMethodID(clazz, "log",
"(Ljava/lang/String;Ljava/lang/String;)V");
jstring s0 = env->NewStringUTF(p0.c_str());
jstring s1 = env->NewStringUTF(p1.c_str());
env->CallVoidMethod(observer, meth, s0, s1);

//TODO: make sure this is called even if there's an exception!
jvm->DetachCurrentThread();
});
} catch (...) {
exc = //handle your exceptions here
}

if (exc != NULL) {
env->Throw(exc);
}
}

关于java - JNI中如何实现观察者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20270120/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com