当前位置: 首页 > 知识库问答 >
问题:

Android JNI中任何线程的FindClass

汝承载
2023-03-14

Android的JNI提示页面提到了这个常见问题:为什么FindClass没有找到我的类?他们提到了多种解决方案,最后一种选择是:

将对ClassLoader对象的引用缓存在方便的地方,并直接发出loadClass调用。这需要一些努力。

所以,我试着让它工作,似乎不管怎样,这种方法根本不适合我。最后,我想出了如何使用类加载器,但如果从本机线程中尝试加载尚未接触/加载的类,它将不起作用。本质上,它与env相同-






编辑:我会提供更多信息来解释我的确切意思。有规则的JNIenv-

我试图从本机c/c访问的类是“com/noname/TestClient”。在myFindClass中,我还使用了env-

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");

我得到这个日志:

myFindClass(“com/noname/TestClent”)=

2)

//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...

//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");

我得到这个日志:

myFindClass(“com/noname/TestClent”)=

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");

我得到这个日志:

myFindClass(“com/noname/TestClent”)=

基本上,我的问题是ClassLoader在第3种情况下找不到我的类。这是一个错误吗?可以做些什么来解决这个问题?

EDIT2:最重要的是,ClassLoader::loadClass显然有问题。如果我问myFindClass(“noname/TestClent”),它会返回一些垃圾,当我以任何方式使用返回的jclass时,应用程序都会崩溃。


共有2个答案

程阳平
2023-03-14

首先尝试将本机线程连接到JVM。

指向jvm的指针,你可以在JNI_OnLoad

env->GetJavaVM(&jvm);

然后从本机线程

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

然后将env用于FindClass

颜阳炎
2023-03-14

在我的应用程序多次尝试并崩溃后,我和一位同事设法在另一个本机线程中缓存并成功使用了类加载器。我们使用的代码如下所示(C 11,但很容易转换为C 2003),发布在这里,因为我们找不到任何上述“将对ClassLoader对象的引用缓存在方便的地方,并直接发出loadClass调用”的示例。这需要一些努力。当从不同于JNI_OnLoad的线程调用findClass时,调用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;
}
 类似资料:
  • 问题内容: 我是python和线程的新手。我已经编写了充当网络爬虫的python代码,并在网站中搜索特定的关键字。我的问题是,如何使用线程同时运行类的三个不同实例。当实例之一找到关键字时,所有三个实例都必须关闭并停止爬网。这是一些代码。 如何使用线程让Crawler同时执行三个不同的爬网? 问题答案: 似乎没有一种(简单的)方法可以终止Python中的线程。 这是一个并行运行多个HTTP请求的简单

  • 我正在使用invokeAll()调用线程列表。AFAIK invokeAll()仅在所有线程完成其任务时才返回。 当所有线程完成时调用 它将停止发生异常的线程,而不停止其余的线程。如果任何一个线程抛出异常,是否有一种方法可以停止所有其他线程?或者我必须提交每个任务而不是invokeAll()?? 按照沃尔特苏的建议,我试着 发生异常时,此操作不会停止

  • 问题内容: 我需要创建一个库,其中将包含同步和异步方法。 -等到得到结果,然后返回结果。 -立即返回Future,如果需要,可以在完成其他操作后进行处理。 我图书馆的核心逻辑 客户将使用我们的库,他们将通过传递构建器对象来调用它。然后,我们将使用该对象构造一个URL,并通过执行该URL对该URL进行HTTP客户端调用,然后将响应作为JSON字符串返回给我们,然后通过创建对象将该JSON字符串发送回

  • Scala中的以下泛型定义有什么不同: 和 我的直觉告诉我它们大致相同,但后者更明确。我发现了一些情况,前者编译了,而后者没有,但我无法确定确切的差别。 谢谢 编辑: 我能再加入一个吗?

  • 我正在创建一个可以监视100-150个设备的监视应用程序...现在要设计一个监视器应用程序,我有两种方法: > < li> 为每个要监控的设备创建一个线程,每个线程将ping(使用ICMP)设备以了解设备是否在线。这些线程将无限期地运行,以便在特定的时间间隔(比如60秒)后了解它们的状态。 创建一个线程池,并为每个设备提交一个任务到一个线程池。任务是简单地 ping 到设备。因此,在当前设计中,任

  • 我是JavaFx/并发的新手,所以我在JavaFX中阅读了并发教程,但是我仍然对JavaFX Gui中后台线程的实现有点困惑。 我试图编写一个与一些串行设备(使用JSSC-2.8)接口的小图形用户界面,并根据这些设备的响应更新图形用户界面。但是,在写入消息和设备响应之间有一个延迟,在任意的时间内使用Thread.sleep()对我来说不是一个可靠的编程方式。因此,我想使用并发包中的等待()和通知(