如何创建静态JNI环境指针?

Vik*_*yan 10 java-native-interface callback

在这里,我在JAVA中创建了一个类,我有一个函数(回调),我必须从C文件中调用它.

class DSMInitializeClassParameter {

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

        // Write Message To Logs.
        System.out.println( "Dsm Initialize Callback called." );
    }
}
Run Code Online (Sandbox Code Playgroud)

为此,我创建了必须调用的本机方法.

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);
}
Run Code Online (Sandbox Code Playgroud)

C文件中我有以下内容:

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 );
}
Run Code Online (Sandbox Code Playgroud)

你怎么看我要打电话(*env)->CallVoidMethod(env, classObject, mid);dsmInitializeCall功能,但我怎么能叫,如果我没有env,classObject而且mid我尝试用静态,但它不能正常工作.

Mic*_*zek 24

缓存实例并继续使用它通常是不安全的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!
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以使用它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);
}
Run Code Online (Sandbox Code Playgroud)

  • @hubatish你的[建议编辑](http://stackoverflow.com/review/suggested-edits/14528119)是关于C++代码的,这个问题是在C语言中 (3认同)

小智 8

确保您将JavaVM作为第一个业务顺序的引用的另一种方法是添加JNI_OnLoad方法并缓存引用.这将在加载共享库时调用.

防爆.

static JavaVM* cachedJVM;

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

一旦获得了JavaVM指针的引用,就可以使用Michael Mrozek在上面的帖子中描述的方法.