我正在尝试为声音流类实现 Java/C++ 绑定(bind)。为了简单起见,我将其简化为它的求法,这足以描述我的问题:
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++ 函数委托(delegate),用作播放流的回调。以具有快进功能的媒体播放器应用为例:
按下“快进”按钮 -> 流媒体库调用 C++ 回调 seek
-> 委托(delegate)给 Java 方法 seek
请注意,这只是一个示例,既不涉及事件调度线程,也不涉及任何其他时髦的东西。
当 JSoundStream
的实例被创建时,将调用一个本地方法来保存 Java VM 指针 (JavaVM*
) 以及 Java 对象引用(作业对象
)。我这样做是因为我无法控制调用回调的确切时间,而且我不知道如何在没有任何 Java 引用的情况下获取 JNI 环境或对象 Activity 。所以我在创建对象时保存了这些信息,我确实有引用。
在 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 对象方法?
最佳答案
你的方法应该是正确的,如果
您的工作项目已通过
binding = env->NewGlobalRef(binding_passed_as_argument);
检索到
不要从同一线程多次调用
AttachCurrentThread
- 使用 TLS 来存储JNIEnv
指针。
关于java - C++调用Java对象方法: Access Violation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5299168/