如何将 jni 用于抽象类?

问题描述 投票:0回答:1

我刚刚熟悉 jni/java 以及我们想要调用用本机代码编写的方法的工作流程,但我尚无法理解的是,如果本机 C++ 库具有像这样的 C++ 抽象类,则如何利用 JNI下面都可以由 C++ 继承来创建具体的 C++ 类,但也可以由 java 类扩展

class NumberInterface {
public:

    using Numbers = std::unordered_set<unsigned int>;
 
    /**
     * Getter to receive all numbers.
     *
     * @return Numbers.
     */
    virtual Numbers getSupportedNumbers() = 0;
 
    virtual bool handleNumber(unsigned int number) = 0;
    virtual bool cancelNumber(unsigned int number) = 0;
 
};

因此,如果这是一个共享库而不是本机端,则某些库可以链接到它,并且它可以具有如下所示的数字类

class Number : public NumberInterface {
public:
    Numbers getSupportedNumbers() override;
 
    bool handleNumber(unsigned int number) override;
    bool cancelNumber(unsigned int number) override;
...
};

到目前为止我无法弄清楚的是,在Java方面,如果我有一个需要使用这个本机实用程序库的库/apk,我如何构建我的实用程序或jni,以便我们可以拥有一个java可以扩展 NumberInterface 的类。

class JavaNumber extends JavaNumberInterfaceEquivalent {
...
}

----编辑添加移动代码片段---

我希望 util 类也有一个 NumberManagerInterface ,如下所示

/// NumberManagerInterface that can handle numbers.
class NumberInterface {
public:
 
    /**
     * Register modules that handle numbers.
     *
     * @return true if successful, false otherwise.
     */
    virtual bool registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module) = 0;
 
    virtual bool handleNumber(const unsigned int number) = 0;
    virtual bool cancelNumber(const unsigned int number) = 0;
 
};

/**
 * Sample NumberManager class.
 *
 */
class NumberManager : public NumberManagerInterface{
public:
    static std::shared_ptr<NumberManagerInterface> createNumberManagerInstance(...);
    bool registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module) override;
    bool handleNumber(const unsigned int number) override;
    bool cancelNumber(const unsigned int number) override;
    ...
private:
    std::vector<std::shared_ptr<NumberModuleInterface>> m_numberHandlers;
    ...
};

bool NumberManager::registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module){
     // do some validation
     m_numberHandlers.insert(module);
     ...
     return true;
}
 
bool NumberManager::handleNumber(const unsigned int number){
  //find the correct handler from m_numberHandlers
  //call the correct handler
  return handler->handleNumber(number);
}
 
void NumberManager::cancelNumber(const unsigned int number){
...
}
java android c++ java-native-interface apk
1个回答
0
投票

从 Java 调用

NumberManager
非常简单:使用一些
native
方法定义 Java 类,并通过参数进行探索。

提供

NumberInterface
的 Java 实现更加复杂。 在Java端,我们定义了一个接口:

// java
interface NumberInterface {
  long[] getSupportedNumbers();
  void handleNumber(long);
  void cancelNumber(long);
  static native void registerNumberInterface(NumberInterface);
}

我们在这里使用

long
,因为Java没有无符号整数。

我们可以像这样定义包装器:

class JavaNumberInterface : public NumberInterface {
  public:
  JavaNumberInterface(jobject o) {
    JNIEnv *env = getEnv();
    obj = env->NewGlobalRef(o);
  }

  Numbers getSupportedNumbers() override {
    JNIEnv *env = getEnv();
    jclass cls = env->GetObjectClass(obj);
    jmethodID mid = env->GetMethodID(cls, "getSupportedNumbers", "()[J");

    jlongArray jarr = (jlongArray) env->CallObjectMethod(obj, mid);
    jsize len = env->GetArrayLength(jarr);
    jlong* arr = env->GetLongArrayElements(jarr, nullptr);

    Numbers ret;
    for (auto x: std::span(arr, len)) {
      ret.insert(int(x));
    }
    env->ReleaseLongArrayElements(jarr);

    env->DeleteLocalRef(jarr);
    env->DeleteLocalRef(cls);
    return ret;
  }
 
  bool handleNumber(unsigned int number) override { /* similar */ }
  bool cancelNumber(unsigned int number) override { /* similar */ }

  private:
    jobject obj;
    JNIEnv *getEnv();
};

registerNumberInterface
的本机实现是:

JNIEXPORT void JNICALL Java_NumberInterface_registerNumberInterface(JNIEnv *env, jclass cls, jobject obj) {
  NumberManager& nm = getNumberManagerSomehow();
  nm.registerNumberModule(std::make_shared<JavaNumberInterface>(obj));
}
© www.soinside.com 2019 - 2024. All rights reserved.