zoukankan      html  css  js  c++  java
  • 怎样在多线程中使用JNI?



    • 假设你想了解JNI在怎样在多线程下使用
    • 假设你在子线程使用JNI时遇到findClass不能找到目标Class,而在主线程下却能找到该Class的问题。或是GetEnv返回NULL的问题
    • 假设你想多学点编程技术的话
    那么,这篇文章就是为你而写的, :)

    近期工作中遇到这么个问题:c++代码须要调用Android的API来做一个比較耗时的任务,由于有点耗时,希望能有个进度条显示给用户,非常自然地,我创建了一个子线程用来执行这个耗时的任务,依照平时写法,结果一执行,GetEnv获取失败了。网上查找一番,官方说明有这么句话:
    If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.

    调试后找到了原因,the current thread is not attached。 原来子线程函数里须要使用AttachCurrentThread()和DetachCurrentThread()这两个函数。没错,你须要gJvm->AttachCurrentThread(&env, NULL);来获取env,这样写之后,以为万事大吉了,结果findClass出错了,没有找到目标类,但是我千真万确地记得在主线程里这么写是没有问题的。env没有问题了,这回又哪里出错了呢?上网google一番,噢,不正确,google被墙了,是用bing查找一番后,总算有些眉目了。

    首先确保你的class name写对了,以包名开头,并用反斜杠隔开。假设class name没有错,那么应该是class loader的问题了。解决方法是你先在主线程中获取该class,而且将其保存为全局变量,以便其它线程使用。
    jclass tmp = env->FindClass("com/example/company/MyClass");  
    myClass = (jclass)env->NewGlobalRef(tmp);

    在子线程中,
    mid = env->GetStaticMethodID(cls, "fromJNI", "(I)V");
    if (mid != NULL)
    {
        env->CallStaticVoidMethod(env, cls, mid, i);
    }
    当然,也有其它解决方法,至少我使用这样的方法成功了。而接下来在java中调用c++的代码就比較顺利了,木有碰到问题了。

    总结:
    1.在JNI_OnLoad中,保存JavaVM*,这是跨线程的,持久有效的,而JNIEnv*则是当前线程有效的。一旦启动线程,用AttachCurrentThread方法获得env。
    2.通过JavaVM*和JNIEnv能够查找到jclass。
    3.把jclass转成全局引用,使其跨线程。
    4.然后就能够正常地调用你想调用的方法了。
    5.用完后,别忘了delete掉创建的全局引用和调用DetachCurrentThread方法。


  • 相关阅读:
    Blend3中创建的Silverlight程序在设计模式下无法显示图片的解决办法
    创建Silverlight Bussiness Application时报错的解决
    .NET 2.0 字符串比较
    ASP.NET 客户端缓存
    AjaxPro部署成功
    遭遇反序列化异常:"在分析完成之前就遇到流结尾"
    正则表达式
    哈哈,终于申请获得批准了!
    ClientScript.RegisterClientScriptInclude注册脚本
    今天经过一场深有体会的谈话终于决定了我2012的方向
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4551392.html
Copyright © 2011-2022 走看看