我有一个使用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 }
我找到了一个可能的解决方案(在此处链接),可以使用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. }