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

原文链接地址:

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);
}

猜你喜欢

转载自blog.csdn.net/u011089570/article/details/70807506