我是java编程的新手,所以如果这听起来像个愚蠢的问题,我会提前道歉。
我正在使用JNI通过创建Swing JFrame来调用C代码并显示它。代码非常简单,如果我将框架可见性设置为false(即调用“hello”方法),Java代码工作正常,而当我将框架可见性设置为true时,没有任何反应(即“hello”方法是不叫)。
Test.java
public class Test extends JFrame {
private JPanel contentPane;
public static Container root;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
Test frame = new Test();
new JNIServer().hello("world"); // where hello is native method
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
JNIServer.java
public class JNIServer{
public native void hello(String name);
static {
System.out.println("Inload library");
System.loadLibrary("JNI_Lib");
}
}
答案 0 :(得分:0)
正如Hovercraft Full Of Eels已经建议的那样,您可以尝试使用单独的线程。我还会尝试添加一些println语句,以查明问题的原因。
为了重现您的问题,我使用Java SE 1.8.0_66-b17(java -version)和gcc(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4(gcc)测试了Ubuntu 14.04 64位 - 版本)。
为了简化一些事情,我没有将String
参数传递给hello
方法/函数,暂时跳过该转换。这些是我用来测试的源文件:
// Test.java
import java.awt.Container;
import javax.swing.*;
public class Test extends JFrame {
private JPanel contentPane;
public static Container root;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
Test frame = new Test();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.callNativeFunction();
System.out.println("Test.main - before setting frame visible");
frame.setVisible(true);
System.out.println("Test.main - after setting frame visible");
} catch (Exception e) {
e.printStackTrace();
}
}
private void callNativeFunction() {
Thread nativeFunctionThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Test.run - before calling hello.");
new JNIServer().hello(); // where hello is native method
System.out.println("Test.run - after calling hello.");
}
});
nativeFunctionThread.start();
}
}
// JNIServer.java
public class JNIServer {
public native void hello();
static {
System.out.println("Inload library");
System.loadLibrary("JNI_Lib");
}
}
// JNIServer.h (generated)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNIServer */
#ifndef _Included_JNIServer
#define _Included_JNIServer
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JNIServer
* Method: hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JNIServer_hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
// JNI_Lib.c
#include <jni.h>
#include <stdio.h>
JNIEXPORT void JNICALL Java_JNIServer_hello(JNIEnv * environment,
jobject java_object) {
printf("Hello from C!\n");
}
为了构建应用程序,我运行了以下命令:
javac Test.java
java Test
javah JNIServer
gcc -fPIC -o libJNI_Lib.so -shared -I /usr/lib/jvm/java-8-oracle/include -I /usr/lib/jvm/java-8-oracle/include/linux JNI_Lib.c -lc
java -Djava.library.path=. Test
这是java -Djava.library.path=. Test
命令的输出:
Test.main - before setting frame visible
Test.run - before calling hello.
Inload library
Hello from C!
Test.run - after calling hello.
Test.main - after setting frame visible
备受期待的&#34;你好,来自C!&#34;被打印了。可以看到(非常小的)框架。 (您可以使用JFrame.setBounds
方法调整帧的大小和位置。)
编辑:使用Eclipse
虽然应该可以合并Java and C project in Eclipse,但我建议从一个较小的步骤开始:使用两个单独的Eclipse项目(甚至更小:创建一个引用CLI创建的库的Java项目C项目)。如果这样做,您可以使用组合的Eclipse项目。
上面的CLI示例使用java.library.path
指向具有libJNI_Lib.so文件的目录。对于Eclipse中的Java项目,可以选择Run |运行Configurations ...菜单,如有必要,在左侧面板中选择Java项目,在右侧面板中选择Arguments选项卡,然后添加&#34; -Djava.library.path =。&#34; (没有引号)到VM参数。例如,请参阅“运行配置”对话框的此屏幕截图: