来自Android JNI中任何线程的FindClass
FindClass from any thread in Android JNI
Android的JNI提示页面提到了此常见问题:为什么FindClass找不到我的班级?他们提到了多种解决方案,最后一个选择是:
缓存在方便的地方对classloader对象的引用,然后发出 LoadClass直接呼叫。这需要一些努力。
所以,我试图使它起作用,似乎无论如何,这种方法根本对我不起作用。最终,我想出了如何使用ClassLoader,但是如果我尝试从尚未触摸/加载的本机线程中,它将无法使用。从本质上讲,从本机线程调用时,行为中的env-> findclass是相同的,但对于已经在应用程序中使用的类,它不会返回0。任何想法,如果我不正确,或者不可能从尚未使用/加载的本机线程中访问类。
编辑:我将提供更多信息来解释我的意思。有常规的JNI env->FindClass(className)
,还有我编写的myFindClass(env, className)
使用的另一个CC_2。
我试图从本机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));
...
}
然后,我有这三种组合来解释这个问题。
1)
//inside JNI_OnLoad thread
myFindClass(env, "com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");
我得到了这个logcat:
myFindClass(" com/noname/testclent")=> c0:0x41b64558,c1:0x41b64558, C0和C1是相同的:1
...
myFindClass(" com/noname/testclent")=> c0:0, C1:0x41B64558,C0和C1是相同的:0
2)
//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...
//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");
我得到了这个logcat:
myFindClass(" 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:
myFindClass(" com/noname/testclent")=> c0:0,c1:0,c0和c1是相同的:1
基本上,我的问题是ClassLoader在第三种情况下找不到我的课程。是一个错误吗?如何解决问题?
edit2:最重要的是,ClassLoader :: LoadClass似乎显然是错误的。如果我询问myFindClass(" noname/testclent"),则它返回一些垃圾,当我以任何方式返回JCLASS时,应用程序崩溃。
在我的应用程序进行了大量尝试和崩溃之后,我和一位同事设法缓存并成功地使用了另一个本机的线程中的类加载程序。我们使用的代码如下所示(C 11,但很容易将其转换为C 2003),此处发布了,因为我们找不到上述任何示例" cache a CACHE a引用classloader对象方便的地方,并发出loadsclass直接打电话。这需要一些努力。"。当从与JNI_ONLOAD不同的线程中调用时,调用FindClass可以很好地工作。我希望这会有所帮助。
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<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;
}
尝试将本机线程连接到JVM。
指向JVM的指针您可以在JNI_OnLoad
env->GetJavaVM(&jvm);
然后从本机线程
JNIEnv *env;
jvm->AttachCurrentThread((void **)&env, NULL);
然后将该env
用于FindClass
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- c++中的线程池
- 线程之间的布尔停止信号
- 为什么std::async使用同一个线程运行函数
- 用于矢量处理的多个线程
- C++为线程工作动态地分割例程
- 来自Android JNI中任何线程的FindClass