FindClass à partir de n'importe quel thread dans Android JNI
Android JNI page conseils mentionne cette FAQ: Pourquoi ne pas FindClass à trouver ma classe?
Ils mentionnent plusieurs solutions et la dernière option est celle-ci:
Cache une référence pour le chargeur de classe de l'objet quelque part est pratique, et la question
loadClass appels directement. Cela nécessite un certain effort.
Donc, j'ai essayé de le faire fonctionner et il semble que peu importe, cette méthode ne fonctionne tout simplement pas pour moi. Finalement, j'ai compris comment utiliser le chargeur de classe, mais cela ne fonctionnera pas si à partir d'un thread natif j'essaie de loadClass qui n'a pas été touché/encore chargé. C'est essentiellement identique à l'env->FindClass de comportement lorsqu'il est appelé à partir d'un thread natif, à l'exception qu'il ne renvoie pas 0 pour les classes qui ont été déjà utilisés dans l'application. Aucune idée si je n'ai pas l'obtenir, ou il est impossible d'accéder aux classes à partir d'un thread natif qui n'étaient pas utilisés ou encore chargé.
EDIT: je vais vous donner plus d'informations pour expliquer exactement ce que je veux dire. Il est régulier de JNI env->FindClass(className)
, et un autre que j'ai écrit myFindClass(env, className)
qui utilise la mise en cache ClassLoader->loadClass
.
La classe que j'essaye d'accéder à de natif c/c++ est "com/noname/TestClient". À l'intérieur de myFindClass j'ai aussi utiliser env->FindClass et journal de la valeur qu'elle renvoie:
jclass myFindClass(JNIEnv * env, const char* 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 are same: %d",
name, c0, c1, env->IsSameObject(c0, c1));
...
}
Ensuite, j'ai ces 3 combinaisons pour expliquer le problème.
1)
//inside JNI_OnLoad thread
myFindClass(env, "com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");
- Je obtenir ce logcat:
myFindClass("com/noname/TestClent") => c0:0x41b64558, c1:0x41b64558,
c0 et c1 sont les mêmes: 1
...
myFindClass("com/noname/TestClent") => c0:0,
c1:0x41b64558, c0 et c1 sont les mêmes: 0
2)
//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");
- Je obtenir ce logcat:
myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0 et c1 sont les mêmes: 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");
- Je obtenir ce logcat:
myFindClass("com/noname/TestClent") => c0:0, c1:0, c0 et c1 sont les mêmes: 1
En gros, mon problème est que le chargeur de classe ne trouve pas de ma classe dans le 3ème cas. Est-ce un bug? Ce qui peut être fait pour résoudre le problème?
EDIT2:
En plus de cela, il semble que le chargeur de classe::loadClass est clairement buggy. Si je demande myFindClass("noname/TestClent") ensuite, il retourne à certaines des ordures, et quand j'utilise ce qui est retourné jclass en aucune façon l'application se bloque.
- Oui, c'est normal, les applications Android ne pas utiliser le système de chargeur de classe par défaut. Juste cache tout que vous avez besoin dans
JNI_OnLoad()
et qui prendra soin de cela. - Re: EDIT2: on dirait que la méthode a déclenché une exception, à quel point la valeur de retour n'est pas défini.
loadClass()
jamais renvoie null; elle renvoie soit la classe de référence ou elle lève une exception. - elle pourrait l'être. Je ne me souviens pas exactement quel était le problème, mais je l'ai résolu par la suite.
Vous devez vous connecter pour publier un commentaire.
Après beaucoup d'essayer et de s'écraser de mon application, un collègue et j'ai réussi à le cache et réussi à utiliser le chargeur de classe dans une autre, natif, fil. Le code que nous avons utilisé est indiqué ci-dessous (C++11, mais peut facilement être converti en C++2003), posté ici car nous n'avons pas trouvé d'exemples de cette "Cache une référence pour le chargeur de classe de l'objet quelque part est pratique, et la question loadClass appels directement. Cela nécessite un certain effort.". L'appel de findClass a parfaitement fonctionné lorsqu'il est appelé à partir d'un thread différent de celui de JNI_OnLoad. J'espère que cette aide.
ClassLoader.loadClass()
ne retourne pas null si la classe n'est pas trouvé. Elle lève une exception, ce qui signifie que la valeur de retour n'est pas défini. Vous devez vérifier les exceptions après l'appel deCallObjectMethod
, et vous ne devez pas utiliser la valeur de retour si une exception a été soulevée. (Ce qui est vrai en général-toutCall*Method
invocation doit être suivie parExceptionCheck
ouExceptionOccurred
, et vous pouvez voir l'exception, dans le journal, avecExceptionDescribe
.)JNI_OnLoad
etfindClass
(surtout le dernier -- vous pouvez convertir une exception à NULL, et claire l'exception, pour obtenir la sémantique que vous voulez). Notez également que vous n'avez pas besoin d'appelerFindClass
pour trouverjava.lang.Class
; vous pouvez simplement utiliserGetObjectClass
sur lejclass
que vous avez déjà (c'est plus rapide et ne manque jamais sur un objet valide). Avez-vous essayé sur Android >= 4.0? Ressemble vous avez besoin d'unNewGlobalRef
surgFindClassMethod
.classClass
nécessaire? Mon code pauses si je plutôt passerrandomClass
enGetMethodID
, mais je ne sais pas pourquoi, puisqu'il devrait être la même chose, non? Est-ce parce que la classe en question estcom/*
? Comment avez-vous su pour ce faire, et il y a toutes les références ou les documents que vous pouvez m'indiquer? Merci!NewGlobalRef()
AVANT ce est stocké dans le monde. l'appel deNewGlobalRef()
à partir d'un autre thread n'est pas d'aller travailler. Faire comme tels:gClassLoader = env->NewGlobalRef(env->CallObjectMethod(myClass, getClassLoaderMethod));
Pour plus de détails voir ici: android-développeurs.blogspot.kr/2011/11/...java.lang.Class
, ce qui est nécessaire pour lagetMethodID
appel depuisgetClassLoader
est un membre dejava.lang.Class
.findClass
sur le même chargeur de classe de référence en même temps? Est-il une différence entrefindClass
etloadClass
? La chaîne de caractères retournée par NewStringUtf doit probablement être supprimé avec DeleteLocalRef?Essayez de fixer votre thread natif de la JVM en premier.
Le pointeur de jvm vous pouvez obtenir la première chose
JNI_OnLoad
Puis, à partir de votre thread natif
Ensuite l'utiliser
env
pourFindClass