Android NDK / General JNI问题:将object / jobject转换为c ++用户defiend类型

时间:2012-05-14 17:37:54

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

我有一个调用我的c ++代码的本机函数调用,这段代码创建了一个用户定义类的实例。

此功能具有以下签名:

public native Object loadEngine(int arg);

在完成此调用之后,我想调用更多本机函数,这些函数将从loadEngine()返回“Object”并对其进行修改或从中请求数据。

签名的一个例子:

public native String loadEngine(Object engine, int queryID);
  1. 甚至可以这样做吗?
  2. 如果可能的话,我如何将我的GameEngine数据类型转换为java Object或jni jobject。
  3. Java会自动将其作为参考传递,以便永远不会被复制,我可以修改它,对吗?
  4. 以下场景会生成一个错误,说它无法将GameEngine转换为jobject,这是可以理解的,但这是我最好的镜头,对Java的经验非常少:

    JNIEXPORT jobject JNICALL Java_package_loadEngine
      (JNIEnv *env, jobject obj, jint arg) {
         GameEngine engine(params);
         return (jobject)engine;
      }
    
    JNIEXPORT jstring JNICALL Java_package_queryAction
      (JNIEnv *env, jobject obj, jobject engine, jint arg) {
         String ret = newString(Integer.toString((GameEngine)engine.unimportant()));
         return ret;
      }
    

    由于我通过jni调用本机java代码到c ++,我不幸地无法将原生函数定义为:

     public native GameEngine loadEngine(int arg);
    

    可以理解,但我似乎无法找到解决方法。

    谢谢,Scarlet。

1 个答案:

答案 0 :(得分:4)

您可以创建包含,拥有和管理本机代码的Java包装器类。例如(在我脑海中,大脑编译):

class GameEngine {
    private long nativeGameEnginePointer;

    private native long loadEngine();
    public GameEngine() {
        super(...);
        nativeGameEnginePointer = loadEngine();
    }

    private native void destroyEngine(long nativePointer);
    protected void finalize() throws Throwable {
        try {
            destroyEngine(nativeGameEnginePointer);
        } finally {
            super.finalize();
        }
    }

    private native double nativePlayGameOrWhatever(long nativePointer);
    public double playGameOrWhatever() {
        return nativePlayGameOrWhatever(nativeGameEnginePointer);
    }
}

在你的JNI实施中:

class CxxGameEngine;

JNIEXPORT jlong JNICALL GameEngine_loadEngine(JNIEnv *env, jobject obj) {
     return (jlong)(new CxxGameEngine(params));
}

JNIEXPORT jvoid JNICALL GameEngine_destroyEngine(JNIEnv *env, jobject obj, jlong nativePointer) {
     delete (CxxGameEngine *)nativePointer;
}

JNIEXPORT jdouble JNICALL GameEngine_nativePlayGameOrWhatever(JNIEnv *env, jobject obj, jlong nativePointer) {
     return ((CxxGameEngine *)nativePointer)->playGameOrWhatever();
}

请注意使用long来表示本机指针。这就是Java运行时在需要时(例如在java.niojava.util.zip包中)这样做的方式。)long而不是int确保类型足够宽以容纳指针甚至在64位系统上。