基于缓存的jobject从本机函数调用Java函数,methodID失败

时间:2013-04-05 02:59:14

标签: android android-ndk java-native-interface

Java来源:

public void onEventListener(final int eventID, final int arg1,
            final long arg2, final String message) 
{
     Log.d("TEST", "onEventListener() is called - eventID = "+eventID);
}

JNI代码:

JavaVM* gJvm = NULL;

pid_t _vm_tid = -1;

JNIEnv * jEnv = NULL;

jclass native_cls_id = NULL;

jmethodID _onEventListenerID=NULL;

jobject m_nativeObj = NULL;

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
        ....

    gJvm = vm;
    _vm_tid = gettid();
        ....
}

//函数

void NotifyFromNative(int eventID, int arg1, long arg2, char* message) {
    LOGD("Receive_Message_Callback is called - eventID = %d",eventID);

    JNIEnv* env = NULL;
    pid_t tid = gettid();
    LOGD("Step 0");
    if (tid != _vm_tid) {

        jint ret = gJvm->AttachCurrentThread(&env, NULL);
        LOGD("Step 1 - tid != _vm_tid ret=%d",ret);

    } else {
        LOGD("Step 1 - tid == _vm_tid");
        gJvm->GetEnv((void**) &env, JNI_VERSION_1_4);
    }
    LOGD("Step 2");

    jstring jstr = env->NewStringUTF(message);
    LOGD("Step 3");

    env->CallVoidMethod(m_nativeObj, _onEventListenerID, eventID, arg1, arg2,
            jstr);
    LOGD("Step 4");
    env->DeleteLocalRef(jstr);

    if (tid != _vm_tid)
        gJvm->DetachCurrentThread();
}

//初始化JNI函数

JNIEXPORT jint JNICALL Java_NativeManager_initialize(JNIEnv * env,
        jobject obj) {

    LOG_UI("Native initialize is called");

    m_nativeObj = env->NewGlobalRef(obj);

    jclass cls = env->FindClass(classPathName);
    if (cls == NULL) {
        LOGE("Can't find class %s", classPathName);
        return 0;
    }

    native_cls_id = (jclass) env->NewGlobalRef(cls);
    _onEventListenerID = env->GetMethodID(native_cls_id, "onEventListener",
                "(IIJLjava/lang/String;)V");

    if (!_onEventListenerID)
        {
         LOGE("Can't find onEventListener Java method");
             return 0;
    }   
        char* message = "test";
    jstring jstr = env->NewStringUTF(message);
        env->CallVoidMethod(m_nativeObj, _onEventListenerID, 1, 1, 1,
                jstr); //This call work well

    NotifyFromNative(0, 1, 1, "test"); //<= problem here

}

Logcat消息

onEventListener() is called - eventID = 1 
Receive_Message_Callback is called - eventID = 0
Step 0
Step 1 - tid == _vm_tid
Step 2
Step 3 
W/dalvikvm(2160): Invalid indirect reference 0x576725d0 in decodeIndirectRef
E/dalvikvm(2160): VM aborting
A/libc(2160): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 2160 ()

问题:

任何人都可以解释为什么调用NotifyFromNative(0,1,1,&#34; test&#34;)会产生问题,尽管创建了对象的全局引用。非常感谢你

2 个答案:

答案 0 :(得分:0)

我发现Android JNI函数不能使用Long参数。因此,我将Long值分解为2个整数值,代码现在正在运行。

答案 1 :(得分:0)

这是一个非常古老的问题,我偶然发现它。但目前的答案是错的。问题出在这里

void NotifyFromNative(int eventID, int arg1, long arg2, char* message) {

应该是

void NotifyFromNative(int eventID, int arg1, jlong arg2, char* message) {

注意jlong​​。 java中的长是64位。 c / c ++中的长期不保证是那么大。 jlong​​确保java中的long兼容类型。