1

背景

我有一个使用 JNI(使用 NDK)在 Java 和 C/C++ 中编码的 android 项目。

我在 java 端创建了一个 Jni java 包装器,它将自己完成所有 Jni 操作,而除了这个包装器之外,没有其他 java 类可以直接访问 jni 操作。

问题

问题是,我希望创建这个包装器的多个实例,而 Jni 部分应该有每个 Jni 包装器的实例。

这是一个问题,因为 Jni 部分为所有实例保存相同的字段。

问题

我该如何解决这个问题,以便对于 jni 包装器的每个 java 实例,在 jni 部分上都会有一个实例?

我在想,也许我可以将所有字段放入一个 C++ 类中,并有一个 init() 函数,该函数将为 JniWrapper 的 CTOR 返回它的一个新实例,从那时起,对于每个需要字段的 JNI 函数,它将获取此类作为参数。也许它可能是这个链接上显示的指针。

可悲的是,我不知道该怎么做。

有人可以帮忙吗?

样本

这是一个示例代码,我希望能让那些不理解这个问题的人更清楚:

java部分:

public class JniWrapper
  {
  static
    {
    System.loadLibrary("JniTest");
    }

  private native void foo(Bitmap bitmap);
  }

jni部分:

...
// sadly, all of those fields are actually a global fields
int _intField;
float _floatField;    
//those are just sample fields. i would also like to store pointers and objects...

JNIEXPORT void JNICALL ...foo(JNIEnv * env, jobject obj, jobject bitmap)
  {
  // do something with the fields, as if they all belong to the JniWrapper, 
  // and no other instances of JniWrapper are allowed to change them
  }
4

2 回答 2

1

您需要在 JNI 端拥有 C++ 类,并且您需要将 C++ 类的一个实例与您的 JNI 包装类的每个实例相关联。您将需要向 C++ 类实例添加本机方法,new并且delete您将需要一种防弹方法来确保delete每次释放 JNI 包装器类的实例时调用 -calling 方法,例如通过close()方法、finally{}块,甚至是一种finalize()方法:这是其使用合法的一种情况。您需要在每个 Java 实例中存储指向 C++ 实例的指针,例如作为 Java long,并且您需要在 C++ 端获取该指针并将其转换为 C++ 类实例以获取每个实例的数据。

于 2013-07-25T01:23:25.287 回答
1

我找到了一个可能的解决方案(此处链接),使用 jlong​​ 或 jobject 作为在 JNI 端创建的对象的句柄(或指针,如果您愿意)。

人们说最好使用 jobject 作为 ByteBuffer 而不是 jlong​​ 以获得更好的兼容性。

解决方案是:

Java端:

private native ByteBuffer init();
private native void foo(ByteBuffer handle);

JNI端:

/**a class to hold the fields*/
class FieldsHolder
  {
  ... //private fields, for each instance
  }

创建 JNI 对象并发送到 java 端:

JNIEXPORT jobject JNICALL ...init(JNIEnv * env, jobject obj)
  {
  FieldsHolder* myClass= new FieldsHolder();
  ... //prepare fields of the class
  return env->NewDirectByteBuffer(myClass, 0);
  }

重用 JNI 对象:

JNIEXPORT void JNICALL ...foo(JNIEnv * env, jobject obj, jobject handle)
  {
  FieldsHolder* myClass= (FieldsHolder*) env->GetDirectBufferAddress(handle);
  //now we can access the fields again.
  }
于 2013-07-27T17:03:40.303 回答