在Java中调用C++
在java中定义类
package com.example.test;
public class CDevice {
public int nMode;
public float nTemp;
}
java中定义native函数setDevice
package com.example.test;
public class DeviceFun {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("test");
}
public native static int setDevice(CDevice device);
public native static int getDevice(CDevice device);
}
此时,函数名setDevice是红色,把鼠标在函数名上悬浮片刻,在弹出的提示框中选择“Create JNI function for test",选择cpp文件,生成函数,添加函数内容即可
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_test_DeviceFun_setDevice(JNIEnv *env, jclass clazz, jobject device) {
jclass objectClass = env->FindClass("com/example/test/CDevice");
if (objectClass == NULL)
{
return -1;
}
jfieldID jMode = env->GetFieldID(objectClass, "nMode", "I");
jfieldID jTemp = env->GetFieldID(objectClass, "nTemp", "F");
if (device == NULL)
{
return -1;
}
int nMode;
if (jMode != NULL)
{
nMode = env->GetIntField(device, jMode);
}
float nTemp;
if (jTemp != NULL)
{
nTemp = env->GetFloatField(device, jTemp);
}
//c++接口:setDevice(nMode, nTemp);
env->DeleteLocalRef(objectClass);
return 0;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_test_DeviceFun_getDevice(JNIEnv *env, jclass clazz, jobject device) {
jclass objectClass = env->FindClass("com/example/test/CDevice");
if (objectClass == NULL)
{
return -1;
}
jfieldID jMode = env->GetFieldID(objectClass, "nMode", "I");
jfieldID jTemp = env->GetFieldID(objectClass, "nTemp", "F");
if (device == NULL)
{
return -1;
}
int nMode;
float nTemp;
//c++接口:getDevice(nMode, nTemp);
if (jMode != NULL)
{
env->SetIntField(device, jMode, nMode);
}
if (jTemp != NULL)
{
env->SetFloatField(device, jTemp, nTemp);
}
env->DeleteLocalRef(objectClass);
return 0;
}
在C++中回调Java
JNI提供了两个特殊函数JNI_OnLoad()和JNI_OnUnload(),分别在加载库和卸载库的时候调用。
可在c++的JNI_OnLoad()中将JavaVM参数保存为全局对象,方便在任何地方获取JNIEnv对象
#include <jni.h>
JavaVM *g_jvm;
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
g_jvm = vm;//获取一个全局的VM指针
JNIEnv *env = NULL;
//通过JavaVM获取JNIEnv,成功后返回JNI_OK
jint result = vm->GetEnv((void **) &env, JNI_VERSION_1_4);
if (result != JNI_OK || env == NULL)
{
return -1;
}
// 返回jni的版本
return JNI_VERSION_1_4;
}
在java中定义回调的接口
public interface INotify
{
void notifyTemp(float nTemp);
}
在java中定义native接口将INotify接口传给c++
public native static int init(INotify notify);
c++中实现native接口init
jobject g_jobj;
jmethodID jmid_notifyTemp;
extern "C"
jint
Java_com_example_test_DeviceFun_init(JNIEnv *env, jclass clazz,
jobject notify)
{
if (g_jobj == NULL)
{
g_jobj = env->NewGlobalRef(notify);
}
env->GetJavaVM(&g_jvm);//JNI_OnLoad保存的全局变量
jclass clz = env->GetObjectClass(g_jobj);
if (clz)
{
jmid_notifyTemp = env->GetMethodID(clz, "notifyTemp", "(F)V");
}
}
c++中的回调函数定义如下
void notifyTemp(float nTemp)
{
JNIEnv *env;
bool isAttached = isAttachedCurrentThread(&env);
if (NULL != env)
{
env->CallVoidMethod(g_jobj, jmid_notifyTemp, nTemp);
}
//可能从C++主动调用
//可能从java调用到c++再调用回java
//所以加该判断
if (isAttached)
{
r_vm->DetachCurrentThread();
}
}