2011-06-01 54 views
11

在这里我创建了一个JAVA类,其中我有必须从C文件中调用的函数(回调函数)。如何创建静态JNI环境指针?

class DSMInitializeClassParameter { 

    /** 
    * Callback function for DSM Initialize. 
    */ 
    public void DSMInitializeCallback() { 

     // Write Message To Logs. 
     System.out.println("Dsm Initialize Callback called."); 
    } 
} 

为此,我创建了必须调用的本地方法。

public class DsmLibraryTest extends Activity { 
    // Some code .... 

    // Create a DSMInitializeClassParameter class object. 
    DSMInitializeClassParameter object = new DSMInitializeClassParameter(); 
    // Call native method with given object. 
    nativeMethod(object); 

    // Some code .... 

    // Implementation of native method. 
    public native int nativeMethod(DSMInitializeClassParameter classObject); 
} 

Ç文件我有以下几点:

dsmResult_t dsmInitializeCall(dsmResult_t status, void * pUserData, dsmEvent_t * hEvent) { 

    (*env)->CallVoidMethod(env, classObject, mid); 
} 

JNIEXPORT jint JNICALL Java_com_Dsm_Test_DsmLibraryTest_nativeMethod(JNIEnv* env, jobject obj, jobject classObject) { 
    // This function loads a locally-defined class. It searches the directories and zip 
    // files specified by the CLASSPATH environment variable for the class with the specified name. 
    jclass cls = (*env)->FindClass(env, "com/Dsm/Test/DSMInitializeClassParameter"); 
    // Get java Method. 
    jmethodID mid = (*env)->GetMethodID(env, cls, "DSMInitializeCallback", "()V"); 
    // If no method was found return -1; 
    if(mid == NULL) { 
     return -1; 
    } 

    // Call DSM Initialize Callback Function and return value. 
    return dsmInitialize(dsmInitializeCall, NULL); 
} 

你怎么看我想打电话给(*env)->CallVoidMethod(env, classObject, mid);dsmInitializeCall功能,但我怎么能叫,如果我没有envclassObjectmid我尝试使用静态但不起作用。

回答

22

它通常是unsafe来缓存一个JNIEnv*实例并继续使用它,因为它根据当前活动的线程而变化。你可以保存一个JavaVM*实例,它永远不会改变。在本地初始化函数,调用GetJavaVM,并将它传递一个JavaVM指针的地址:

static JavaVM *jvm; 
JNIEXPORT void JNICALL Java_SomeClass_init(JNIEnv *env, jclass) { 
    int status = (*env)->GetJavaVM(env, &jvm); 
    if(status != 0) { 
     // Fail! 
    } 
} 

现在你可以使用JavaVM*来获取当前JNIEnv*AttachCurrentThread

dsmResult_t dsmInitializeCall(dsmResult_t status, void * pUserData, dsmEvent_t * hEvent) { 
    JNIEnv *env; 
    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL); 
    (*env)->CallVoidMethod(env, classObject, mid); 
} 
+0

非常感谢,我会在明天检查我的工作场所......可能你可以帮助我解决这个问题吗? http://stackoverflow.com/questions/6152747/jni-not-support-types-as-void-unsigned-int-what-to-do – 2011-06-01 20:04:14

+0

为什么我不能使用jclass cls =(* env) - > GetObjectClass( env,classObject);而不是jclass cls =(* env) - > FindClass(env,“com/Dsm/Test/DSMInitializeClassParameter”);我认为classObject是我的类的对象,我有DSMInitializeCallback,所以我可以从该对象获取类。但是,当我尝试应用程序崩溃与Dalvic虚拟机错误....但为什么? – 2011-06-02 05:35:50

+0

http://stackoverflow.com/questions/6184678/where-can-i-see-message-from-jni-printf-in-eclipse – 2011-06-02 08:35:44

6

另一种方法来确保您获得对JavaVM的参考,因为第一个业务订单是添加JNI_OnLoad方法并缓存参考。这将在共享库加载时调用。

Ex。

static JavaVM* cachedJVM; 

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) 
{ 
    cachedJVM = jvm; 
    // ... Any other initialization code. 
} 

一旦有裁判在JavaVM指针就可以使用在上述柱中描述的方法Michael Mrozek

+0

为什么它必须是静态JavaVM *而不仅仅是JavaVM *?为什么它必须是静态的? – pdiddy 2014-03-07 13:41:58

+0

为了将JavaVM变量限制在声明它的文件中。 – Gio 2015-09-19 22:26:21