我正在使用 JNI 调用一个静态 java 方法,该方法又创建一个 Swing JFrame 并显示它。代码相当简单,Java 代码独立工作(即java StartAWT
做它应该做的),而当使用 JNI 从 C 调用时,进程挂起。
我在 Mac OS X 10.8 Mountain Lion 上使用 JDK 1.7.0_09。
这是我用来调用静态方法的 C 代码:
JavaVM* jvm;
JNIEnv* env = create_vm(&jvm);
jclass class = (*env)->FindClass(env, "StartAWT");
jmethodID method = (*env)->GetStaticMethodID(env, class, "run", "()V");
(*env)->CallStaticVoidMethod(env, class, method);
(*jvm)->DestroyJavaVM(jvm);
该类StartAWT
如下所示:
public class StartAWT {
public static class Starter implements Runnable {
public void run() {
System.out.println("Runnning on AWT Queue.");
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("That's a frame!");
JLabel label = new JLabel("A Label");
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
public static class GUI implements Runnable {
public void run() {
try {
System.out.println("Going to put something on the AWT queue.");
SwingUtilities.invokeAndWait(new Starter());
} catch (Exception exc) {
throw new RuntimeException(exc);
}
}
}
public static void run() {
Thread gui = new Thread(new GUI());
gui.start();
}
}
当我启动应用程序时,我确实看到Going to put something on the AWT queue
但没有看到Running on AWT Queue
.
我相信我的 C 进程中的虚拟机没有 AWT 事件队列,但我不知道如何设置它以拥有一个(我也不确定这是原因)。
为了使用 JNI 显示基于 AWT 的 GUI,需要做什么?
--
编辑:我已经插入循环来查看哪些线程是活动的,哪些不是(可以在这个 gist中看到)。在这个版本中,我SwingUtilities.invokeAndWait
在另一个线程中调用。结果:主线程处于活动状态(C)。Java 调度的第一个线程(不是主线程)是存活的;执行 Call 的线程invokeAndWait
被阻塞(我认为 invokeAndWait 甚至没有返回),甚至没有输入应该在 EventQueue 上运行的函数。
我也尝试过SwingUtilities.invokeAndWait
直接调用,这将给出以下消息:
2013-02-02 13:50:23.629 swing[1883:707] Cocoa AWT: Apple AWT Java VM was loaded on first thread -- can't start AWT. (
0 liblwawt.dylib 0x0000000117e87ad0 JNI_OnLoad + 468
1 libjava.dylib 0x00000001026076f1 Java_java_lang_ClassLoader_00024NativeLibrary_load + 207
2 ??? 0x000000010265af90 0x0 + 4335185808
)
这也是我在 StackOverflow 上的其他问题中读到的内容,例如下面评论中建议的问题。但是,我找不到原始问题的解决方案。也许值得注意的是,在上面的消息出现后,主线程仍然活着,即进程既没有死锁也没有崩溃。
--
编辑:我在 Linux 上测试了它按预期工作的代码。所以我相信这是 Cocoa AWT 的 Mac OS X 问题,但我不知道如何规避它。
--
编辑:我还尝试将 JVM 的整个调用移动到一个新的本机线程上。这适用于具有 Apples Java 32 位 (1.6.0_37) 的 Mac OS X 10.6,但会导致与上述相同的死锁。在 Mac OS X 10.8 上情况更糟,应用程序崩溃,只有一条消息“Trace/BPT trap: 5”(这似乎与加载动态库有关)。
根据 Apples Launch Services Reference的说法,我还尝试按照此 Q&A中的描述捆绑二进制文件,但启动失败并显示消息,这是一个未知错误。后者也发生在没有尝试使用 AWT 的情况下(单纯的 JVM 调用失败)。lsopenurlswithrole() failed with the message -10810