在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文档中的“本地和全局引用”部分。

07-28 00:58