在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
之间有任何冲突吗?是虫子吗?如何解决该问题?
最佳答案
不要这样做:
gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
特别是,切勿获取本地引用(即
CallObjectMethod
返回的内容)并将其存储在除本地变量之外的任何内容中。如果要在获取本地引用的函数之外访问该值,则需要使用
NewGlobalRef
获取全局引用。一旦执行返回到该线程中的VM,本地引用将无效。请参见JNI Tips文档中的“本地和全局引用”部分。