FindClass from any thread in Android JNI

前端 未结 2 1302
孤独总比滥情好
孤独总比滥情好 2020-11-28 02:42

Android\'s JNI tips page mentions this FAQ: Why didn\'t FindClass find my class? They mention multiple solutions and the last option there is this one:

<
2条回答
  •  我在风中等你
    2020-11-28 03:25

    After much trying and crashing of my app, a colleague and I managed to cache and succesfully use the class loader in another, native, thread. The code we used is shown below (C++11, but easily converted to C++2003), posted here since we couldn't find any examples of the aforementioned "Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.". Calling findClass worked perfectly when called from a thread different from the one of JNI_OnLoad. I hope this helps.

    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);
        gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
                                        "(Ljava/lang/String;)Ljava/lang/Class;");
    
        return JNI_VERSION_1_6;
    }
    
    jclass findClass(const char* name) {
        return static_cast(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));
    }
    
    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;
    }
    

提交回复
热议问题