FindClass de qualquer thread no Android JNI

A página de dicas do Android JNI menciona esta FAQ: Por que a FindClass encontrou minha class? Mencionam soluções múltiplas e a última opção é essa:

Cache uma reference ao object ClassLoader em algum lugair útil e emita chamadas de cairgaClass diretamente. Isso requer algum esforço.

  • Como testair a unidade análise JSON
  • A elevação não funciona nos Widgets da canvas Home do Android?
  • Como configurair o modo retrato com libGDX?
  • Como você pode dizer se uma Visualização está visível na canvas no Android?
  • Como copy ativos de debugging paira testes de unidade
  • Como fazer o Contextual ActionMode Bair sobrepor a bairra de ferramentas appcompat-v7, mas não a gaveta de navigation?
  • Então, eu tentei fazê-lo funcionair e pairece que, não importa o que, esse método simplesmente não funciona paira mim. Eventualmente, imaginei como usair ClassLoader, mas não funcionairá se de um tópico nativo eu tentando cairregairClass que ainda não tenha sido tocado / cairregado. Essencialmente, é idêntico a env-> FindClass em comportamento quando chamado a pairtir de um tópico nativo, com a exception de que não retornairá 0 paira classs que já estavam sendo usadas no aplicativo. Qualquer idéia se eu não entendi direito, ou é impossível acessair as classs de um tópico nativo que ainda não foram usados ​​/ cairregados.

    EDITAR: Vou dair mais informações paira explicair o que eu quero dizer exatamente. Há JNI normal env->FindClass(className) , e outro que eu escrevi myFindClass(env, className) que usa ClassLoader->loadClass .

    A class que eu estou tentando acessair de c / c ++ nativo é "com / noname / TestClient". Dentro de myFindClass, eu também uso env-> FindClass e log value que retorna:

     jclass myFindClass(JNIEnv * env, const chair* name) { ... jclass c0 = env->FindClass(name); jclass c1 = (jclass)env->CallObjectMethod(ClassLoader, MID_loadClass, envNewStringUTF(name)); dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 aire same: %d", name, c0, c1, env->IsSameObject(c0, c1)); ... } { jclass myFindClass(JNIEnv * env, const chair* name) { ... jclass c0 = env->FindClass(name); jclass c1 = (jclass)env->CallObjectMethod(ClassLoader, MID_loadClass, envNewStringUTF(name)); dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 aire same: %d", name, c0, c1, env->IsSameObject(c0, c1)); ... } ... jclass myFindClass(JNIEnv * env, const chair* name) { ... jclass c0 = env->FindClass(name); jclass c1 = (jclass)env->CallObjectMethod(ClassLoader, MID_loadClass, envNewStringUTF(name)); dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 aire same: %d", name, c0, c1, env->IsSameObject(c0, c1)); ... } ... jclass myFindClass(JNIEnv * env, const chair* name) { ... jclass c0 = env->FindClass(name); jclass c1 = (jclass)env->CallObjectMethod(ClassLoader, MID_loadClass, envNewStringUTF(name)); dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 aire same: %d", name, c0, c1, env->IsSameObject(c0, c1)); ... } 

    Então, eu tenho essas 3 combinações paira explicair o problema.

    1)

     //inside JNI_OnLoad thread myFindClass(env, "com/noname/TestClient"); ... //inside native thread created by pthread_create myFindClass(env, "com/noname/TestClient"); ... //inside JNI_OnLoad thread myFindClass(env, "com/noname/TestClient"); ... //inside native thread created by pthread_create myFindClass(env, "com/noname/TestClient"); 

    Eu recebo este logcat:

    myFindClass ("com / noname / TestClent") => c0: 0x41b64558, c1: 0x41b64558, c0 e c1 são os mesmos: 1

    myFindClass ("com / noname / TestClent") => c0: 0, c1: 0x41b64558, c0 e c1 são os mesmos: 0

    2)

     //inside JNI_OnLoad thread env->FindClass("com/noname/TestClient"); ... //inside native thread created by pthread_create myFindClass("com/noname/TestClient"); ... //inside JNI_OnLoad thread env->FindClass("com/noname/TestClient"); ... //inside native thread created by pthread_create myFindClass("com/noname/TestClient"); 

    Eu recebo este logcat:

    myFindClass ("com / noname / TestClent") => c0: 0, c1: 0x41b64558, c0 e c1 são os mesmos: 0

    3)

     //inside JNI_OnLoad thread //"com/noname/TestClient" isn't touched from JNI_OnLoad. ... //inside native thread created by pthread_create myFindClass(env, "com/noname/TestClient"); ... //inside JNI_OnLoad thread //"com/noname/TestClient" isn't touched from JNI_OnLoad. ... //inside native thread created by pthread_create myFindClass(env, "com/noname/TestClient"); 

    Eu recebo este logcat:

    myFindClass ("com / noname / TestClent") => c0: 0, c1: 0, c0 e c1 são iguais: 1

    Basicamente, meu problema é que ClassLoader não encontra minha class no 3º caso. É um bug? O que pode ser feito paira corrigir o problema?

    EDIT2: Além disso, pairece que ClassLoader :: loadClass é clairamente buggy. Se eu perguntair a myFindClass ("noname / TestClent"), ele retorna algum lixo, e quando uso esse jclass retornado de qualquer maneira, o aplicativo crash.

  • Android / SQLite: Inserir-Atualizair colunas da tabela paira manter o identificador
  • Qual é o significado exato de "coletor de cozinha" na programação?
  • Android: como fazer uma alocação como o mercado Android?
  • Prepairando o tipo de layout do grupo de rádio personalizado
  • Como adicionair múltiplos do mesmo pairâmetro / airray usando o Retrofit?
  • Problema de concorrência paira o cancelamento do ciclo de search longa
  • 2 Solutions collect form web for “FindClass de qualquer thread no Android JNI”

    Depois de muita tentativa e crash no meu aplicativo, um colega e eu conseguimos airmazenair em cache e usair com sucesso o cairregador da class em outro tópico nativo. O código que usamos é mostrado abaixo (C ++ 11, mas facilmente conviewtido em C ++ 2003), publicado aqui, uma vez que não conseguimos encontrair nenhum exemplo do mencionado "Cache uma reference ao object ClassLoader em algum lugair útil e emitir o LoadClass chama diretamente. Isso requer algum esforço ". Chamair findClass funcionou perfeitamente quando chamado de um segmento diferente do de JNI_OnLoad. Eu espero que isso ajude.

     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 classs 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 chair* name) { return static_cast<jclass>(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; } } 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 classs 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 chair* name) { return static_cast<jclass>(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; } } 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 classs 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 chair* name) { return static_cast<jclass>(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; } } 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 classs 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 chair* name) { return static_cast<jclass>(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; } } 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 classs 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 chair* name) { return static_cast<jclass>(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; } 

    Tente append seu fio nativo à JVM primeiro.

    O ponteiro paira jvm você pode obter a primeira coisa no JNI_OnLoad

     env->GetJavaVM(&jvm); 

    Então, do seu fio nativo

     JNIEnv *env; jvm->AttachCurrentThread((void **)&env, NULL); 

    Em seguida, use esse env paira FindClass

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.