【发布时间】:2014-11-05 02:26:48
【问题描述】:
在 android 中我使用 pthread_create 创建一个本地线程,然后在 Callback 过程中,调用 FindClass 来获取一个 Java 类。但它不起作用。我从android jni tips得到提示 我在FindClass from any thread in Android JNI找到了解决方案
我像这样为我的项目修改它 [编辑]
JavaVM* gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gJvm = pjvm; // cache the JavaVM pointer
auto env = getEnv();
//replace with one of your classes in the line below
auto randomClass = env->FindClass("com/example/RandomClass");
jclass classClass = env->GetObjectClass(randomClass);
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
"()Ljava/lang/ClassLoader;");
gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
gClassLoader = env->NewGlobalRef(gClassLoader);
gFindClassMethod = env->GetMethodID(classLoaderClass, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
//check. this is ok
jclass cls = env->FindClass("com/example/data/DataTest");
jmethodID methoID = env->GetMethodID(cls, "name", "()Ljava/lang/String;");
LOG_INFO("cls is %p\n", cls);
return JNI_VERSION_1_6;
}
JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if(status < 0) {
status = gJvm->AttachCurrentThread(&env, NULL);
if(status < 0) {
return nullptr;
}
}
return env;
}
jclass findClass(const char* name) {
JNIEnv *env = getEnv();
jclass resultClass = 0;
if(env)
{
resultClass = env->FindClass(name);
//it can not found class in native thread, use loadClass method
if (!resultClass)
{
LOG_INFO("can not find the class");
//return value is not null.
return static_cast<jclass>(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
}
}
return resultClass;
}
.......
//thread callback
void *proc(void *)
{
JNIEnv *env = getEnv();
jclass cls = findClass("com/example/data/DataTest");
if (cls)
{
LOG_INFO("GetMethodID");
//crash
jmethodID methodID = env->GetMethodID(cls, "name", "()Ljava/lang/String;");
LOG_INFO("proc tag is %p\n", tag);
}
}
.....
pthread_create(&handle, NULL, proc, 0);
.....
程序在 env->GetMethodID 处退出。我收到此错误:
Invalid indirect reference 0x40d8bb20 in decodeIndirectRef.
如果我从 findClass 中删除 resultClass = env->FindClass(name);,就可以了。可以打印“proc tag is”。
//correct
jclass findClass(const char* name) {
JNIEnv *env = getEnv();
jclass resultClass = 0;
if(env)
{
if (!resultClass)
{
return static_cast<jclass>(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
}
}
return resultClass;
}
env->FindClass(name); 和 env->CallObjectMethod to loadClass 之间有任何冲突吗?
这是一个错误吗?有什么办法可以解决这个问题?
【问题讨论】:
-
JNIEnv* 指针是否正确获取成功?您还可以发布 getEnv() 函数的代码吗?错误是 FindClass() 还是 CallObjectMethod() 调用产生的?
-
@mario_qiu 哦,拜托。您可以亲眼看到 cmets 中的代码完全难以辨认。将其编辑到您的帖子中。
-
代码中缺少如何以及何时获取
gJvm,这也很重要。 -
您的代码是否在
findClass的if (!resultClass)分支中执行? -
是的。在使用 pthread_create 函数创建的本机线程中,env->FindClass 返回 null
标签: java android c++ android-ndk java-native-interface