Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java androidjni返回多个变量_Java_Android_Java Native Interface - Fatal编程技术网

Java androidjni返回多个变量

Java androidjni返回多个变量,java,android,java-native-interface,Java,Android,Java Native Interface,如何从jni函数返回多个变量,避免数组管理的开销?您可以使用包装器。然后返回包装器。首先创建一个包含一些内部变量的类,这些变量是您想要返回的多个变量。然后使用这个类作为返回类型。我可以想出三种不同的方法 回调 从JNI代码中调用一个包含多个参数的Java方法,在Java代码中的某个地方设置一个变量,从该方法返回时可以检索该变量 JNIEXPORT void JNICALL Java_my_package_name_JNIReturnExample_returnWithJavaCallback(J

如何从
jni
函数返回多个变量,避免数组
管理的开销?

您可以使用包装器。然后返回包装器。首先创建一个包含一些内部变量的类,这些变量是您想要返回的多个变量。然后使用这个类作为返回类型。

我可以想出三种不同的方法

回调

从JNI代码中调用一个包含多个参数的Java方法,在Java代码中的某个地方设置一个变量,从该方法返回时可以检索该变量

JNIEXPORT void JNICALL Java_my_package_name_JNIReturnExample_returnWithJavaCallback(JNIEnv *env, jobject javaThis, jfloat param1, jfloat param2)
{
    // Get the class of the current calling object
    jclass clazz = (*env)->GetObjectClass(env, javaThis);

    // Get the method id of the instance method: void javaCallback(float, float) in my.package.name.JNIReturnExample
    jmethodID callback = (*env)->GetMethodID(env, clazz, "javaCallback", "(FF)V");

    // Calls my.package.name.JNIReturnExample#javaCallback(float, float);
    (*env)->CallVoidMethod(env, javaThis, callback, param1, param2);
}

返回一个新的Java对象

在JNI中实例化Java对象(my.package.name.JNIReturnExample),并将其返回给Java

JNIEXPORT jobject JNICALL Java_my_package_name_JNIReturnExample_returnObjectValue(JNIEnv *env, jobject javaThis, jfloat param1, jfloat param2)
{
    // Get the class we wish to return an instance of
    jclass clazz = (*env)->FindClass(env, "my/package/name/JNIReturnObject");

    // Get the method id of an empty constructor in clazz
    jmethodID constructor = (*env)->GetMethodID(env, clazz, "<init>", "()V");

    // Create an instance of clazz
    jobject obj = (*env)->NewObject(env, clazz, constructor);

    // Get Field references
    jfieldID param1Field = (*env)->GetFieldID(env, clazz, "param1", "F");
    jfieldID param2Field = (*env)->GetFieldID(env, clazz, "param2", "F");

    // Set fields for object
    (*env)->SetFloatField(env, obj, param1Field, param1);
    (*env)->SetFloatField(env, obj, param2Field, param2);

    // return object
    return obj;
}

请注意,无论您决定使用哪种方法,都应该缓存各种JNI类型
jclass、jmethodID、jfieldID
,因为JNI查找操作很慢,实际上只需要执行一次


缓存

要在回调方法中缓存JNI引用,并使用方法调用它们,请执行以下操作:

static jclass myCallbackClass;
static jmethodID myCallbackMethod;

/**
 * Call this method in JNI_OnLoad
 */ 
void CacheCallback()
{
    // Get a reference to the Callback class
    jclass clazz = (*env)->FindClass(env, "my/package/name/JNIReturnExample");

    // Store a global reference, since the local one will be freed when returning from the function.
    myCallbackClass = (*env)->NewGlobalRef(env, clazz);

    // Get a reference to the static callback method
    jmethodID callback = (*env)->GetStaticMethodID(env, myCallbackClass, "jniCallback", "(II)V");

    // jmethodID doesn't need a NewGlobalRef call
    myCallbackMethod = callback;
}

/**
 * Call this method in JNI_OnUnload
 */
void ReleaseCallback()
{
    (*env)->DeleteGlobalRef(env, myCallbackClass);
    myCallbackClass = NULL;

    // jmethodIDs are safe to keep without an explicit global reference, for this reason, we don't need to delete the reference either.
    myCallbackMethod = NULL;
}

还有一种方法-jobjectArray

就我个人而言,我需要返回Java一对字符串和int

使用env->NewStringUTF方法可以很容易地将字符串放入这样的数组中 但对于int,必须构造包装器

本地部分:

extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_example_myapp_CallingClass_writeCfgFile(
    JNIEnv *env,
    jobject obj,
    jobjectArray stringArray,
    jstring filepath){
...     
    std::pair<int,string> ret = generate_config(filePath, reqMsgTypes);

    jobjectArray retobjarr = (jobjectArray)env->NewObjectArray(2, env->FindClass("java/lang/Object"), NULL);
    env->SetObjectArrayElement(retobjarr, 0, NewInteger(env, ret.first));
    env->SetObjectArrayElement(retobjarr, 1, env->NewStringUTF(ret.second.c_str()));

    return retobjarr;
}

jobject NewInteger(JNIEnv* env, int value){
    jclass integerClass = env->FindClass("java/lang/Integer");
    jmethodID integerConstructor = env->GetMethodID(integerClass, "<init>", "(I)V");
    return env->NewObject(integerClass, integerConstructor, static_cast<jint>(value));
}

你能提供一个你想返回什么样的数据结构的例子,这将使回答你的问题更容易。我想返回2个floats。这与JNI无关,请解释如何返回包装器。你能给出一个基本的例子吗?我想从一个函数返回2个浮点变量。。这可以在不通过env变量进行数组管理或类解析的情况下完成吗(太慢)?嘿,使用第一个方法(回调),我可以缓存回调指针,比如说作为全局jni变量,以便进一步使用(离开函数后)?我编辑了答案,以显示缓存回调类和方法的方法。缓存该方法最简单的方法是使用静态方法,因为这些方法不需要jobject。答案很好!我认为这可能是最快的方法了,不是吗?我相信是的,但是您也可以通过缓存jclass和jmethodID引用来加快“返回Java对象”方法的速度。然后,您可以使用带参数的构造函数而不是SetField,这将把操作减少到两个JNI调用!谢谢
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_example_myapp_CallingClass_writeCfgFile(
    JNIEnv *env,
    jobject obj,
    jobjectArray stringArray,
    jstring filepath){
...     
    std::pair<int,string> ret = generate_config(filePath, reqMsgTypes);

    jobjectArray retobjarr = (jobjectArray)env->NewObjectArray(2, env->FindClass("java/lang/Object"), NULL);
    env->SetObjectArrayElement(retobjarr, 0, NewInteger(env, ret.first));
    env->SetObjectArrayElement(retobjarr, 1, env->NewStringUTF(ret.second.c_str()));

    return retobjarr;
}

jobject NewInteger(JNIEnv* env, int value){
    jclass integerClass = env->FindClass("java/lang/Integer");
    jmethodID integerConstructor = env->GetMethodID(integerClass, "<init>", "(I)V");
    return env->NewObject(integerClass, integerConstructor, static_cast<jint>(value));
}
Object[] resp = writeCfgFile( msgTypes,  filePath");
Integer i = (Integer)resp[0];
String str = (String)resp[1];