1

我有一个带有本机代码的 Android 应用程序。如何在调用本地方法之间保存对对象的引用?

// 1: create native object and hold it
Object obj = jni_wrapper.native_getObject();

// ... do smth

// 2: return an object back to native code
Object result = jni_wrapper.native_doSmthWithObject(obj);

因此,代码应该保存对对象的引用并以某种方式找到它(在上面的示例中,介于 1: 和 2: 之间)。我可以创建自己的类和特殊的实例字段(如果需要)来保存引用。

我使用了下一个解决方案(只是在 Index 对象的“指针”实例字段中保存指向实例的指针),但它似乎不起作用。

Java(索引.java):

/**
 *  CXIndex
 */
public class Index {

    private long pointer;

    public long getPointer() {
        return pointer;
    }
}

本机代码:

// index
static jclass IndexClass;
static jmethodID IndexConstructor;
static jfieldID IndexPointerField;

void bindIndex(JNIEnv *env)
{
    IndexClass = env->FindClass("name/antonsmirnov/xxx/dto/Index");
    IndexConstructor = env->GetMethodID(IndexClass, "<init>", "()V");
    IndexPointerField = env->GetFieldID(IndexClass, "pointer", "J");
}

// map CXIndex
jobject mapIndex(JNIEnv *env, CXIndex *index)
{
    if (IndexClass == NULL)
        bindIndex(env);


    jobject obj = env->NewObject(IndexClass, IndexConstructor);
    jlong jpointer = reinterpret_cast<jlong>(index);

    env->SetLongField(obj, IndexPointerField, jpointer);
    return obj;
}

// map Index -> CXIndex
CXIndex unmapIndex(JNIEnv *env, jobject jindex)
{
    if (IndexClass == NULL)
        bindIndex(env);

    jlong jpointer = env->GetLongField(jindex, IndexPointerField);
    CXIndex *ptr = reinterpret_cast<CXIndex*>(jpointer);
    return *ptr;
}

这与可以带来特定行为的Android有关!

4

2 回答 2

2

这里至少有两个问题。

  1. 您不能持有对 ajobject或 a的静态引用jclass。你需要一个GlobalReforWeakGlobalRef来做到这一点。
  2. 您的 JNI 代码中完全没有错误检查。GetClass()GetMethodID()GetFieldID()、等的结果GetLongField()必须全部检查,并且还检查未决异常。

但是我不明白你为什么需要这个。您的第一个解决方案要容易得多,并且可以通过将私有本机方法包装在调用它们并自动提供所需对象的公共 Java 方法中来无形地实现,其中可以将对象存储在具有本机方法的类中。

于 2017-06-20T04:12:15.577 回答
1

你可以创建一个函数

jlong JNI_mypackage_myclass_createMyNativePeer() {

      return new MyNativePeer();
}

然后在 Java 中,您将返回的值保留在您的类中。

class MyWrapper {
    private long mPeer;

    public void createPeer() {
       mPeer = createMyNativePeer();
    }

   private native long createMyNativePeer();

   public void controlPeer(int param) {
            controlPeer(mPeer, param);
   }

   private native void controlPeer(long peer, int param);

}

然后将该值传递给控制函数:

jvoid JNI_mypackage_myclass_controlPeer(jlong peer, int someParam) {
      ((*MyNativePeer)peer)->doSomething(param);
}
于 2013-10-04T14:40:37.573 回答