Я использую JNI для вызова статического java-метода, который, в свою очередь, создает Swing JFrame и отображает его. Код довольно прост, и Java-код работает автономно (т.е. java StartAWT
делает то, что он должен), тогда как при вызове из C с использованием JNI процесс зависает.
Я использую JDK 1.7.0_09 для Mac OS X 10.8 Mountain Lion.
Это код 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 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, но я не знаю, как ее настроить для ее использования (и я не уверен, что это причина).
Что нужно сделать, чтобы показать графический интерфейс на основе AWT с использованием JNI?
-
EDIT: Я вставил циклы, чтобы увидеть, какие потоки живы, а какие нет (можно увидеть в this gist). В этой версии я делаю вызов SwingUtilities.invokeAndWait
в другом потоке. Результат: основная нить живая (C). Первый поток, отправленный Java (а не основной поток), жив; поток, выполняющий вызов 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, например, в комментариях ниже. Однако я не мог найти решение исходной проблемы. Возможно, стоит отметить, что после того, как появилось вышеприведенное сообщение, основной поток все еще жив, т.е. Не затормозился и не сработал процесс.
-
EDIT: Я тестировал код в Linux, где он работает как ожидалось. Поэтому я считаю, что это проблема Mac OS X с Cocoa AWT, но я не знаю, как обойти ее.
-
EDIT: Я также попытался переместить весь вызов JVM на новый собственный поток. Это работает на Mac OS X 10.6 с 32-битным ядром Java (1.6.0_37), но приводит к тому же тупику, который описан выше. В Mac OS X 10.8 это хуже, а приложения - с единственным сообщением "Trace/BPT trap: 5" (что связано с загрузкой динамических библиотек).
Я также попытался связать двоичный файл, как описано в этом Q & A, но запуск завершился неудачно с сообщением lsopenurlswithrole() failed with the message -10810
, которое является неизвестной ошибкой, согласно Яблоки Справочное руководство по запуску. Последнее также происходит, не пытаясь использовать AWT (простое вызов JVM не работает).