您的位置:首页 > 编程语言 > C语言/C++

使用JNI在JAVA和C++之间进行交互操作

2017-04-26 16:36 656 查看
原文链接地址:

https://library.vuforia.com/articles/Solution/How-To-Communicate-Between-Java-and-C-using-the-JNI

本文旨在描述如何使用JNI(Java Native Interface)实现JAVA和C++之间的互相调用。

1.在JAVA中调用C++方法

假设在ImageTargets.java中,C++方法会被声明为以public native开头的函数,例如:public native int initTracker();

在C++代码文件ImageTargets.cpp 中函数会被声明为:

#include <jni.h>
#ifdef __cplusplus
extern "C"
{
#endif
JNIEXPORT int JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initTracker(JNIEnv *, jobject)
{
...
}
#ifdef __cplusplus
}
#endif


首先,需要注意的是所有在C++中暴漏的JNI函数都被extern"C"代码块包裹,函数的返回值的前后会有两个宏:JNIEXPORT 和JNICALL。函数名也必须遵循一定的格式:Java_package_class_function。在Java中你可以像调用其他Java函数一样调用JNI函数,例如:

int result = initTracker();


2.在JNI函数中调用Java代码
假设在ImageTargets.java中有函数:

public int getTextureCount() {     return mTextures.size(); }


你如果想在C++中调用上面的函数,首先需要从ImageTargets对象查询隶属的ImageTargets类,然后在ImageTargets类中查找getTextureCount 函数,具体实现的C++代码如下:

JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initApplicationNative(
JNIEnv* env, jobject obj, jint width, jint height)
{
...
jclass activityClass = env->GetObjectClass(obj);
jmethodID getTextureCountMethodID = env->GetMethodID(activityClass,
"getTextureCount", "()I");
if (getTextureCountMethodID == 0)
{
LOG("Function getTextureCount() not found.");
return;
}
textureCount = env->CallIntMethod(obj, getTextureCountMethodID);
...
}


下面解释一下GetMethodID 函数的最后一个参数“()I”:

将Java函数的参数类型依次放在小括号内;

在小括号后面添加返回值类型;

例如(IF)Z代表入参一个Int一个Float,返回值为Boolean

3.在非JNI函数中调用Java代码

为了在C++中调用Java代码,我们需要JNIEnv对象和Jobject,在JNI函数中这没有问题,因为JNIEnv 和Jobject为前两个入参,但是如果你想在其他的非JNI函数中调用Java函数,就需要将JNIEnv 和Jobject保存为全局变量。

但是将JNIEnv 保存为全局变量是非常危险的,因为JNIEnv不是线程安全的,下面的代码演示了一种安全的方法来使用JNIEnv,那就是使用NewGlobalRef来对Jclass和Jobject做全局的引用:

JavaVM* javaVM = NULL;
jclass activityClass;
jobject activityObj;
JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initApplicationNative(
JNIEnv* env, jobject obj, jint width, jint height)
{
env->GetJavaVM(&javaVM);
jclass cls = env->GetObjectClass(obj);
activityClass = (jclass) env->NewGlobalRef(cls);
activityObj = env->NewGlobalRef(obj);
}
void myNativeMethod()
{
JNIEnv *env;
javaVM->AttachCurrentThread(&env, NULL);
jmethodID method = env->GetMethodID(activityClass, "myJavaMethod", "()V");
env->CallVoidMethod(activityObj, method);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: