我正在尝试在 android 中使用 JNI 来制作一个函数指针,我正在使用的 native 库使用它转发它对 java 的调用。
调用initializeStateController
时,会使用pthread_create
创建一个新线程,只要State Controller 的状态发生变化,它就会调用函数指针。
但是,当我尝试在 C 中从 state_exec
调用 GetStaticMethodID
时,出现以下错误:
JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference: 0xec500019 (0xdead4321) in call to GetStaticMethodID
这是我当前的代码:
C 代码
state_controller *controller;
JavaVM* gJvm = NULL;
static jclass sc_class;
JNIEnv* getEnv() {
JNIEnv *env;
int status = (*gJvm)->GetEnv(gJvm, (void**)&env, JNI_VERSION_1_6);
if(status < 0) {
status = (*gJvm)->AttachCurrentThread(gJvm, &env, NULL);
if(status < 0) {
return NULL;
}
}
return env;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* pjvm, void* reserved) {
gJvm = pjvm;
JNIEnv *env = getEnv();
sc_class = (*env)->FindClass(env, "com/my/package/StateController");
return JNI_VERSION_1_6;
}
int state_exec(int state, int from) {
JNIEnv *env = getEnv();
jmethodID mid = (*env)->GetStaticMethodID(env, sc_class, "stateExec","(II)I");
jint result = (*env)->CallStaticIntMethod(env, sc_class, mid, state, from);
return (int) result;
}
// This part is unimportant.
// This is just where I hand the function pointer
// to the library to use.
JNIEXPORT void JNICALL
Java_com_my_package_StateController_initializeStateController
(
JNIEnv *env,
jobject jobj
) {
controller = new_state_controller(
state_exec
);
sc_start_controller(controller);
}
Java
package com.my.package;
class StateController {
public native void initializeStateController();
public static int stateExec(int state, int from) {
Log.d("StateTest", "State " + state + " -> " + from);
return 0;
}
}
. . .
(new StateController()).initializeStateController();
最佳答案
事实证明,FindClass
方法只返回本地引用,而不是全局引用。为了完成这项工作,您需要将其设为全局引用。您可以按照下面的说明执行此操作。
// Replace
sc_class = (*env)->FindClass(env, "com/my/package/StateController");
// With
sc_class = (*env)->NewGlobalRef(
env,
(*env)->FindClass(
env,
"com/my/package/StateController"
)
);
// Later when you are done with the class reference, run this to free it.
(*env)->DeleteGlobalRef(env, sc_class);
来自 Android 文档:
Bug: Mistakenly assuming FindClass() returns global references
FindClass() returns local references. Many people assume otherwise. In a system without class unloading (like Android), you can treat jfieldID and jmethodID as if they were global. (They’re not actually references, but in a system with class unloading there are similar lifetime issues.) But jclass is a reference, and FindClass() returns local references. A common bug pattern is “static jclass”. Unless you’re manually turning your local references into global references, your code is broken.
https://android-developers.googleblog.com/2011/11/jni-local-reference-changes-in-ics.html
关于java - 使用 JNI 从单独的线程调用静态 Java 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46332147/