Android NDK / General JNI 问题:将对象/jobject 转换为 c++ 用户 defiend

Android NDK / General JNI issue: Converting object / jobject to c++ user defiend type

本文关键字:转换 jobject 用户 defiend 对象 c++ General NDK JNI 问题 Android      更新时间:2023-10-16

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

此函数具有以下签名:

public native Object loadEngine(int arg);

完成此调用后,我想调用更多本机函数,这些函数将获取从 loadEngine(( 返回的"对象"并对其进行修改,或从中请求数据。

签名示例:

public native String loadEngine(Object engine, int queryID);
  1. 甚至有可能做到这一点吗?
  2. 如果可能的话,我将如何将我的游戏引擎数据类型转换为java Object或jni jobject。
  3. Java会自动将其作为引用传递,这样它就不会被复制,我可以修改它,对吧?

以下场景生成一个错误,指出它无法将游戏引擎转换为 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);

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

谢谢,斯嘉丽。

您可以创建包含、拥有和管理本机代码的 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 位系统上也能容纳指针。