1

描述

在我的 C++ 应用程序类JNIXMLDocument中进行了一些 JAVA 方法调用。在JNIXMLDocument类的构造函数中,我附加当前线程并将其设置为我的类成员JNIEnv* m_JavaEnv,然后在所有方法中使用它。同样在构造函数中,我试图找到我的 JAVA 类com/fido/android/framework/service/XMLDOMDocument并将其设置为类成员m_XMLDocumentClass,并从类中获取该类对象并将其设置为类成员m_XMLDocumentObject

C++ 代码

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&m_JavaEnv, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&m_JavaEnv, NULL);
        }

        /* Get Class from Java **/
        m_XMLDocumentClass = m_JavaEnv->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (m_XMLDocumentClass != NULL) {
            /* Call java class constructor. **/
            jmethodID constructor = m_JavaEnv->GetMethodID(m_XMLDocumentClass , "<init>", "()V");
            m_XMLDocumentObject = m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);    

        }

    }

    bool Initialize()
    {
        jmethodID method = m_JavaEnv->GetMethodID(m_XMLDocumentClass, "Initialize", "()Lorg/w3c/dom/Document;");
        jobject document = m_JavaEnv->CallObjectMethod(m_XMLDocumentObject , method);

    }

    private:
        JNIEnv* m_JavaEnv;
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

C++ 代码(正确的方式)

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        JNIEnv* env;
        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&env, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&env, NULL);
        }

        /* Get Class from Java **/
        jclass localClass = env->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (localClass != NULL) {
            m_XMLDocumentClass = env->NewGlobalRef(localClass);
            /* Call java class constructor. **/
            jmethodID constructor = env->GetMethodID(localClass, "<init>", "()V");
            jobject localObject = env->NewObject(m_XMLDocumentClass , constructor);    
            m_XMLDocumentObject = env->NewGlobalRef(localObject );
        }

    }

    bool Initialize()
    {

    }

    private:
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

问题

  1. 在构造函数中设置一次JNI接口指针(JNIEnv* m_JavaEnv)并在整个代码中使用它是否正确?
  2. jclass m_XMLDocumentClass在构造函数中设置而不是在所有方法中使用该变量是否正确?
  3. jobject m_XMLDocumentObject以这种方式在构造函数中设置是否正确,m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);或者我必须调用NewGlobalRef.
  4. 如果我的应用程序不在同一个线程中工作(使用多个线程),会出现什么问题?
4

1 回答 1

3

在构造函数中设置一次JNI接口指针(JNIEnv* m_JavaEnv)并在整个代码中使用它是否正确?

不,它是线程特定的。这就是 Attach/DetachCurrentThread 的用途。唯一可行的方法是在同一个线程中构造和销毁 C++ 对象。

在构造函数中设置 jclass m_XMLDocumentClass 并在所有方法中使用该变量是否正确?

不,它是一个本地引用,当它获取的JNI方法返回时它就会过期。您必须保存为全局或弱引用,除非它仅用于单个 JNI 方法中。

Is it right to set jobject m_XMLDocumentObject in the constructor in this way m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);

否:见上文。

或者我必须打电话给 NewGlobalRef。

是的,如上所述。

如果我的应用程序不在同一个线程中工作(使用多个线程),会出现什么问题?

主要是JVM崩溃。JVM 假定您遵循 JNI 规范中的所有规则。就这样做吧。

于 2012-06-12T08:39:58.893 回答