JNI - 如何使用具有不同字段的多个Jni包装器实例?

时间:2013-07-24 21:01:12

标签: java android-ndk java-native-interface field instance-variables

背景

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

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

问题

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

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

问题

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

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

遗憾的是,我不知道该怎么做。

有人可以帮忙吗?

样品

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

java部分:

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

  private native void foo(Bitmap bitmap);
  }

jni part:

...
// 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
  }

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

我找到了一个可能的解决方案(链接here),要么使用jlong​​或jobject作为在JNI端创建的对象的句柄(或指针,如果你愿意的话)。 / p>

人们说最好使用作为ByteBuffer的jobject而不是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.
  }