【问题标题】:Passing multiple arguments for callback function in java from native c code (JNI)从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数
【发布时间】:2017-11-28 10:14:52
【问题描述】:

以下代码从本地 c 代码调用 java 中的回调函数,传递一些字符串数据作为参数。

原生C层

jmethodID statusId = env->GetMethodID(pctx->jniHelperClz, "CallbackHandler", "(Ljava/lang/String;)V");
jstring string_data = env->NewStringUTF((const char*)"SOME_STRING_DATA");
env->CallVoidMethod(pctx->jniHelperObj, statusId, string_data);
env->DeleteLocalRef(string_data);

Android / Java(回调处理程序)

@Keep
private void CallbackHandler(String string_data) {
    // Some Code
}

除了字符串,我还想传递一个 int 类型的数据。我的 java 回调处理程序如下所示。我应该在我的原生层中进行哪些更改以支持两个参数。

@Keep
private void CallbackHandler(String string_data, int int_data) {
    // Some Code
}

【问题讨论】:

  • 所以在调用CallVoidMethod时添加jint参数——它的签名是:void CallVoidMethod(jobject obj, jmethodID methodID, ...)
  • 您需要编辑函数指针CallVoidMethod 的参数以在结构env 中多出一个int
  • GetMethodID 的最后一个参数,即 ("(Ljava/lang/String;)V") 也必须更改对吗?
  • 正确:签名也必须更改 - 使用 javap 打印出来

标签: java android c++ c java-native-interface


【解决方案1】:

您需要将方法签名从(Ljava/lang/String;)V 更改为(Ljava/lang/String;I)V

jmethodID statusId = env->GetMethodID(pctx->jniHelperClz, “CallbackHandler”, "(Ljava/lang/String;I)V”);

另外,您使用DeleteLocalRef() 的方式不正确。此方法用于删除通过NewLocalRef() 创建的本地引用,但NewStringUTF() 不会创建它们。方法NewStringUTF() 在垃圾收集器控制的Java 堆中创建jstring 对象。您无需手动删除。

注意:

本地引用在本地方法调用期间有效。在本机方法返回后,它们会自动释放。每个本地引用都会消耗一定数量的 Java 虚拟机资源。程序员需要确保本地方法不会过度分配本地引用。虽然本地方法返回 Java 后会自动释放本地引用,但过多分配本地引用可能会导致 VM 在本地方法执行期间耗尽内存。

您需要使用DeleteLocalRef() 来立即删除大对象(例如在循环中)。

【讨论】:

  • “它们在本机方法返回后自动释放” OP 是从本机代码调用 Java,而不是相反。如果本地方法没有返回 Java(或者如果/当本地线程与 VM 分离时),本地引用将不会被自动删除。
  • 有趣的想法,@Michael。我可以在哪里阅读更多相关信息?可能你有代码示例的链接吗?
  • 我不确定是否有任何好的文档来描述这一点。但是您可以查看 Android 的运行时实现以了解在不同情况下会发生什么,例如android.googlesource.com/platform/dalvik.git/+/… 中的 Jni.cpp 和 Thread.cpp(是的,现在 Android 使用 Art 而不是 Dalvik,但 Dalvik 源代码通常更易于浏览)。
  • 感谢您的链接,@Michael。我没想到你建议阅读android平台的完整源代码:)
  • 谢谢@Sergey。下面的代码对我有用。 methodID statusId = env->GetMethodID(pctx->jniHelperClz, “CallbackHandler”, "(Ljava/lang/String;I)V”);jstring string_data = env->NewStringUTF((const char*)"SOME_STRING_DATA");jint int_data = 10; // some numberenv->CallVoidMethod(pctx->jniHelperObj, statusId, string_data, int_data);env->DeleteLocalRef(string_data);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多