2013-02-12 113 views
3

所以我一直试图从C++调用java方法,但没有任何运气。这是错误,我得到:JNI - 从C++调用Java方法

JNI ERROR(应用错误):访问过时的本地参考0x5cb00019在0xdeadd00d(索引 6大小为2的表) VM中止 致命信号11(SIGSEGV)(代码= 1)

以下是我在代码执行(Java端):

public class Wrapper extends Activity{ 
     private native void initJNIBridge(); 
      static final String TAG = "Wrapper"; 

    protected void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 

      initJNIBridge(); // Calls C++ function. 
    } 

    public void upgradeAdFree() { 
      Log.d(TAG, "Wrapper::upgradeAdFree()"); 
    } 

这里是C++方面:

typedef struct JniMethodInfo_ 
    { 
     JNIEnv * env; 
     jclass  classID; 
     jmethodID methodID; 
    } JniMethodInfo; 

    extern "C" 
    { 
static jobject javaObj; 

// get env and cache it 
static JNIEnv* getJNIEnv(void) 
{ 

    JavaVM* jvm = cocos2d::JniHelper::getJavaVM(); 
    if (NULL == jvm) { 
     LOGD("Failed to get JNIEnv. JniHelper::getJavaVM() is NULL"); 
     return NULL; 
    } 

    JNIEnv *env = NULL; 
    // get jni environment 
    jint ret = jvm->GetEnv((void**)&env, JNI_VERSION_1_4); 

    switch (ret) { 
     case JNI_OK : 
      // Success! 
      return env; 

     case JNI_EDETACHED : 
      // Thread not attached 

      // TODO : If calling AttachCurrentThread() on a native thread 
      // must call DetachCurrentThread() in future. 
      // see: http://developer.android.com/guide/practices/design/jni.html 

      if (jvm->AttachCurrentThread(&env, NULL) < 0) 
      { 
       LOGD("Failed to get the environment using AttachCurrentThread()"); 
       return NULL; 
      } else { 
       // Success : Attached and obtained JNIEnv! 
       return env; 
      } 

     case JNI_EVERSION : 
      // Cannot recover from this error 
      LOGD("JNI interface version 1.4 not supported"); 
     default : 
      LOGD("Failed to get the environment using GetEnv()"); 
      return NULL; 
    } 
} 

// get class and make it a global reference, release it at endJni(). 
static jclass getClassID(JNIEnv *pEnv) 
{ 
    jclass ret = pEnv->FindClass(CLASS_NAME); 
    if (! ret) 
    { 
     LOGD("Failed to find class of %s", CLASS_NAME); 
    } 

    return ret; 
} 
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *methodName, const char *paramCode) 
{ 
    jmethodID methodID = 0; 
    JNIEnv *pEnv = 0; 
    bool bRet = false; 

    do 
    { 
     pEnv = getJNIEnv(); 
     if (! pEnv) 
     { 
      break; 
     } 

     jclass classID = getClassID(pEnv); 

     methodID = pEnv->GetMethodID(classID, methodName, paramCode); 
     if (! methodID) 
     { 
      LOGD("Failed to find method id of %s", methodName); 
      break; 
     } 

     methodinfo.classID = classID; 
     methodinfo.env = pEnv; 
     methodinfo.methodID = methodID; 


     bRet = true; 
    } while (0); 

    return bRet; 
} 

JNIEXPORT void JNICALL Java_org_test_games_Wrapper_initJNIBridge(JNIEnv *, jobject jobj){ 
    LOGD("Java_org_test_games_Wrapper_initJNIBridge()"); 

    javaObj = jobj; 

    return; 
} 

void upgradeAdFreeJNI() 
{  
    LOGD("upgradeAdFreeJNI"); 

    JniMethodInfo methodInfo; 
    if (! getMethodInfo(methodInfo, "upgradeAdFree", "()V")) 
    { 
     LOGD("Cannot find method!"); 
     return; 
    } 

    methodInfo.env->CallVoidMethod(javaObj, methodInfo.methodID); 
} 


} 

在这里的任何建议将不胜感激,因为我已经被困在这几天,它不是世界上最简单的任务来调试。

感谢

回答

4

的问题是,你的静态指针到您的jobject不再有效。你需要保护它免受任何垃圾收集器的运行。这可以通过使用全局引用而不是本地引用来完成。 而不是仅仅分配指针创建一个globalRef。

JNIEXPORT void JNICALL Java_org_test_games_Wrapper_initJNIBridge(JNIEnv *, jobject jobj) 
{ 
    LOGD("Java_org_test_games_Wrapper_initJNIBridge()"); 

    javaObj = env->NewGlobalRef(env, jobj); 

return; 
} 

但请注意,您还必须释放globafRef。

+0

感谢mkaes您的回复!那就是诀窍。 – kub 2013-02-12 16:52:52