从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数
Posted
技术标签:
【中文标题】从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数【英文标题】:Passing multiple arguments for callback function in java from native c code (JNI) 【发布时间】: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
打印出来
【参考方案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 number
env->CallVoidMethod(pctx->jniHelperObj, statusId, string_data, int_data);
env->DeleteLocalRef(string_data);
以上是关于从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数的主要内容,如果未能解决你的问题,请参考以下文章