我正在尝试为声音流类实现Java / C ++绑定。为了保持我的例子简单,我将把它简化为它的搜索方法,这足以描述我的问题:
public abstract class JSoundStream extends SoundStream {
public abstract void seek(float timeOffset);
}
为了测试,我使用以下实现:
@Override public void seek(float timeOffset) {
System.out.println("seek(" + timeOffset + ")");
}
seek
方法是一种回调方法,由本机C ++函数委托,该函数用作播放流的任何内容的回调。以具有快进功能的媒体播放器应用程序为例:
按下“快进”按钮 - >流媒体库调用C ++回调seek
- >委托Java方法seek
注意这只是一个例子,事件调度线程和其他任何其他功能都没有。
当创建JSoundStream
的实例时,将调用本机方法,该方法将同时保存Java VM指针(JavaVM*
)以及Java对象引用(jobject
) 。我这样做是因为我无法控制何时调用回调,并且我知道无法获得JNI环境或没有Java引用的 live 对象。所以我在创建对象时保存了这些信息,在那里我有参考文献。
在C ++ seek
方法内部,我试图以这种方式调用Java seek
方法:
virtual void OnSeek(float timeOffset) {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
env->CallVoidMethod(binding, m_seek, (jfloat)timeOffset);
}
其中binding
是jobject
,jvm
Java VM指针和m_seek
我之前获得的jmethodID
方法的seek
。
但是,CallVoidMethod
的调用将导致jvm.dll
中的访问冲突。所有的指针和值对我能说的都有效,并确保Java对象不会被垃圾收集。我相信存储jobject
和/或Java VM指针是问题的根源,但是我再也看不清楚原因,因为这些值在程序运行时没有变化。
有人看到我接近这个问题的方式有问题吗?如何 - 如果没有存储引用 - 我会从C ++代码调用Java对象方法吗?
答案 0 :(得分:3)
如果
,您的方法应该是正确的已使用binding = env->NewGlobalRef(binding_passed_as_argument);
您不会多次从同一个线程调用AttachCurrentThread
- 使用TLS存储JNIEnv
指针。