【问题标题】:env->FindClass function returns nullenv->FindClass 函数返回 null
【发布时间】:2012-12-20 05:22:18
【问题描述】:

我正在尝试从我的 cpp 类调用我的 java 类中的一些函数。我成功地进行了三次这些调用,直到我第四次调用函数。我正在使用 cocos2dx 引擎。

我从 MiscManagerJni.cpp 调用 MiscManager.java 中的函数

当我尝试获取 classID 并且游戏崩溃时出现以下错误:

12-20 12:06:09.328: W/System.err(26651): java.lang.NoClassDefFoundError: [通用] 12-20 12:06:09.328: W/System.err(26651): at dalvik.system.NativeStart.main(Native Method) 12-20 08:56:35.402: D/libMiscManager(25952): 找不到 com/games/Game/MiscManager 的类

我已经从 MiscManagerJni.cpp 类中成功调用了 MiscManager.java 类中的函数 3 次。但是当我调用时,第 4 次返回 null

jclass ret = pEnv->FindClass(CLASS_NAME);

谁能告诉我是什么导致了这个错误。

这些是我用来获取方法 id 和类 id 的函数

#define  LOG_TAG    "libMiscManager"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  CLASS_NAME "com/games/Game/MiscManager"

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


extern "C"

{
    // 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
            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 getStaticMethodInfo(cocos2d::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->GetStaticMethodID(classID, methodName, paramCode);

        if (! methodID)
        {
            LOGD("Failed to find static method id of %s", methodName);
            break;
        }
        methodinfo.classID = classID;
        methodinfo.env = pEnv;
        methodinfo.methodID = methodID;

        bRet = true;
    } while (0);
    return bRet;


   }

 void InitJni()
      {
        cocos2d::JniMethodInfo methodInfo;
        if (! getStaticMethodInfo(methodInfo, "Init", "()V"))
        {
            return ;
        }

    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

void SaveBooleanJni(const char *key, bool value)
    {
         cocos2d::JniMethodInfo methodInfo;
        if (! getStaticMethodInfo(methodInfo, "SaveBoolean", "(Ljava/lang/String;Z)V"))
        {
        return;
    }

    jstring stringArg = methodInfo.env->NewStringUTF(key);
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg, value);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

void SaveIntegerJni(const char *key, int value)
{
    cocos2d::JniMethodInfo methodInfo;
    if (! getStaticMethodInfo(methodInfo, "SaveInteger", "(Ljava/lang/String;I)V"))
    {
        return;
    }

    jstring stringArg = methodInfo.env->NewStringUTF(key);
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg, value);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

void SaveLongJni(const char *key, long value)
{
    cocos2d::JniMethodInfo methodInfo;
    if (! getStaticMethodInfo(methodInfo, "SaveLong", "(Ljava/lang/String;J)V"))
    {
        return;
    }
    jstring stringArg = methodInfo.env->NewStringUTF(key);
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg, value);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

long GetLongJni(const char *key, long defaultValue)
{
     cocos2d::JniMethodInfo methodInfo;
    long ret = 0;
    if (! getStaticMethodInfo(methodInfo, "GetInteger", "(Ljava/lang/String;J)J"))
    {
        return ret;
    }

    jstring stringArg = methodInfo.env->NewStringUTF(key);
    ret = methodInfo.env->CallStaticLongMethod(methodInfo.classID, methodInfo.methodID, stringArg, defaultValue);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);

    return (long)ret;
}

bool GetBooleanJni(const char *key, bool defaultValue)
{
     cocos2d::JniMethodInfo methodInfo;
    jboolean ret = false;
    if (! getStaticMethodInfo(methodInfo, "GetBoolean", "(Ljava/lang/String;Z)Z"))
    {
        return ret;
    }
     jstring stringArg = methodInfo.env->NewStringUTF(key);
    ret = methodInfo.env->CallStaticIntMethod(methodInfo.classID, methodInfo.methodID, stringArg, defaultValue);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);

    return ret;
}

int GetIntegerJni(const char *key, int defaultValue)
{
    cocos2d::JniMethodInfo methodInfo;
    int ret = 0;
    if (! getStaticMethodInfo(methodInfo, "GetInteger", "(Ljava/lang/String;I)I"))
    {
        return ret;
    }

    jstring stringArg = methodInfo.env->NewStringUTF(key);
    ret = methodInfo.env->CallStaticIntMethod(methodInfo.classID, methodInfo.methodID, stringArg, defaultValue);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);

    return (unsigned int)ret;
}

bool IsConnectedToNetworkJni()
{
    cocos2d::JniMethodInfo methodInfo;
    jboolean ret = false;
    if (! getStaticMethodInfo(methodInfo, "IsConnectedToNetwork", "()Z"))
    {
        return ret;
    }

    ret = methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);

    return ret;
}
}

【问题讨论】:

  • getStaticMethodInfo(methodInfo, "SaveLong", "(Ljava/lang/String;J)V") : com/games/Game/MiscManager 参考在哪里?对我来说,似乎缺少一个参数类名。
  • 对不起,我已经添加了其余的函数,你可以看到我已经定义了类名
  • 你能展示适用于其他调用的代码吗?它在找不到类时失败似乎很奇怪,而我们预计找不到方法或其他问题......
  • 我已经在 jni 类中添加了所有其他功能
  • 也许 java 类没有在 pkg 中更新或者在缓存中所以它不包含新的 SaveLong 方法?

标签: java android c++ java-native-interface cocos2d-x


【解决方案1】:

我通过在 cocos2dx 引擎中使用 JNIHelper 类解决了这个问题。 我在 JNIHelper 类中使用了 getStaticMethodInfo,而不是在我自己的类中编写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 2018-12-06
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    相关资源
    最近更新 更多