安卓JNI技巧页面提到了这个FAQ:为什么FindClass找不到我的类?,其中列举了多种解决方案,最后一个方案是:
编辑:我将提供更多信息来解释我的意思。有常规的JNI env->FindClass(className),还有另一个我编写的myFindClass(env, className),它使用缓存的ClassLoader->loadClass。
我正在尝试从本地C/C++访问的类是“com/noname/TestClient”。在myFindClass中,我还使用env->FindClass并记录它返回的值:
然后,我有以下3种组合来解释这个问题。 1)
我得到了这个logcat:
我得到了这个logcat:
我的findClass("com/noname/TestClent") => c0:0,c1:0x41b64558,c0和c1是相同的:0
3)
我得到了以下的logcat:
我的问题在于ClassLoader在第三种情况下无法找到我的类。这是一个错误吗?有什么方法可以解决这个问题吗?
此外,看起来ClassLoader::loadClass是有缺陷的。如果我要求myFindClass("noname/TestClent"),它会返回一些垃圾,并且当我以任何方式使用该返回的jclass时,应用程序会崩溃。
所以,我尝试让它工作,但似乎无论如何,这种方法对我都根本不起作用。最终,我想出了如何使用ClassLoader,但如果从本地线程中尝试加载尚未被触摸/加载的类,则它将无法工作。实质上,在从本地线程调用时,它与env->FindClass的行为相同,唯一的例外是对于已在应用程序中使用的类,它不会返回0。任何想法,如果我理解得不对或者从本地线程中访问尚未使用/加载的类是不可能的。在方便的地方缓存ClassLoader对象的引用,并直接发出loadClass调用。这需要一些努力。
编辑:我将提供更多信息来解释我的意思。有常规的JNI env->FindClass(className),还有另一个我编写的myFindClass(env, className),它使用缓存的ClassLoader->loadClass。
我正在尝试从本地C/C++访问的类是“com/noname/TestClient”。在myFindClass中,我还使用env->FindClass并记录它返回的值:
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));
...
}
然后,我有以下3种组合来解释这个问题。 1)
//inside JNI_OnLoad thread
myFindClass(env, "com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");
我得到了这个logcat:
2)myFindClass("com/noname/TestClent") => c0:0x41b64558, c1:0x41b64558, c0和c1相同: 1
...
myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0和c1不同: 0
//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");
我得到了这个logcat:
我的findClass("com/noname/TestClent") => c0:0,c1:0x41b64558,c0和c1是相同的: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");
我得到了以下的logcat:
我的问题在于ClassLoader在第三种情况下无法找到我的类。这是一个错误吗?有什么方法可以解决这个问题吗?
此外,看起来ClassLoader::loadClass是有缺陷的。如果我要求myFindClass("noname/TestClent"),它会返回一些垃圾,并且当我以任何方式使用该返回的jclass时,应用程序会崩溃。
JNI_OnLoad()
中缓存所需的所有内容,问题就会得到解决。 - Samuel AudetloadClass()
永远不会返回null;它要么返回类引用,要么抛出异常。 - fadden