【问题标题】:JNI - how to use multiple Jni wrapper instances with different fields?JNI - 如何使用具有不同字段的多个 Jni 包装器实例?
【发布时间】:2013-07-24 21:01:11
【问题描述】:

背景

我有一个使用 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部分:

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

【问题讨论】:

  • 我的印象是您应该能够从 JNI 代码访问 JniWrapper 字段。 NDK不可能吗?我问是因为我不明白你为什么需要将这些字段保留在 JNI 端
  • 有些字段对于 JNI 部分来说是非常私有的,我不想转换它们。其中一些也非常大,需要大量工作才能转换。我不希望它们存储在 JniWrapper 类上,只存储在 Jni 部分上。我希望 JniWrapper 具有用作 Jni 部分主机的最少功能。
  • @c.s.如果你觉得我问这个问题的原因很有趣,请查看这篇文章:stackoverflow.com/questions/17900732/…

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


【解决方案1】:

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

【讨论】:

  • 根据我所阅读的内容,不建议将指针作为 java long 进行存储。使用 ByteBuffer 更好。我在这里发布了如何做这样的事情的完整示例。另外,如果你觉得我问这个问题的原因很有趣,答案是:stackoverflow.com/questions/17900732/…
  • 这是很久以前的事了。对不起。我不记得了... :(
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多