Android JNI错误:NoSuchMethodError:没有非静态方法

huangapple go评论83阅读模式
英文:

Android JNI Error: NoSuchMethodError: no non-static method

问题

我尝试的内容如下。

  1. Java -> 调用 C++ 函数 A
  2. C++ 函数 A 调用 C++ 函数 B
  3. C++ 函数 B 调用 Java 方法 C

我必须存储 JVM(2)和全局 jobject(3)。

但是在第 3 部分,

JNI DETECTED ERROR IN APPLICATION: JNI CallVoidMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method "Lpackage/name/here/d/b;.setInput([F)V"

我总是遇到这个错误。


代码

结构

  • Wrapper.java
  • native-lib.cpp
  • Wrapper.cpp

** <-> 表示通信

其他 Java 类 <-> Wrapper.java

Wrapper.java <-> native-lib.cpp

native-lib.cpp <-> Wrapper.cpp

Wrapper.cpp <-> 其他 C++ 类


Wrapper.java

private static long wrapperAddr = 0; //稍后初始化

private tfModel model;
private native void nativeSetModel(long native_ptr, tfModel model);

public Wrapper(...){
    ...

    model = tfModel.create(tfModel.Model.MNIST, tfModel.Device.CPU, 1);
    nativeSetModel(wrapperAddr, model);
}

native-lib.cpp

extern "C" JNIEXPORT void JNICALL
Java_package_name_here_jni_Wrapper_nativeSetModel(JNIEnv *env,
                                                      jobject instance,
                                                      jlong native_ptr,
                                                      jobject model){
  
  auto wrapper = reinterpret_cast<Wrapper *>(native_ptr);
  
  wrapper->setModel(env, model);
}

Wrapper.cpp

void setModel(JNIEnv *env, jobject _model){
    env->GetJavaVM(&translater::jvm);    
    jobject gmodel = env->NewGlobalRef(_model);    
    translater::model = gmodel;
}

函数 A

...
translater::setInputTS(input1, 100);  // 错误从这里开始

...

translater.h / translater.cpp (函数 B)

class translater{
public:
    
    inline static JavaVM *jvm = nullptr;
    inline static jobject model = nullptr;
    
    // 来源:https://stackoverflow.com/a/30026231/8176989
    static bool GetJniEnv(JavaVM *vm, JNIEnv **env);  
    
    static void predictTS(std::vector<float> &output);

    static void translater::setInputTS(float* input, int len) {
    
    
    JNIEnv *env;
    bool did_attach = GetJniEnv(jvm, &env);

    if(did_attach){
        
        
        jclass clazz = env->GetObjectClass(model);
        jmethodID jid_input = env->GetMethodID(clazz, "setInput", "([F)V");  // 这里是出错的地方

    }

    ...    
};

tfModel.java

public abstract class tfModel{
...

    public void setInput(float[] array){
        if(inputIndex < inputImageNum)
            setInput_Image(inputIndex, array);
        else
            setInput_Tensor(inputIndex - inputImageNum, array);
            
        ++inputIndex;
    }

}

如何正确调用
jmethodID jid_input = env->GetMethodID(clazz, "setInput", "([F)V");

英文:

What I'm trying to do is simplified below.

  1. Java -> Call C++ function A
  2. C++ function A calls C++ function B
  3. C++ function B calls Java method C

I have to store JVM(2) and global jobject(3).

But at part 3,

JNI DETECTED ERROR IN APPLICATION: JNI CallVoidMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method &quot;Lpackage/name/here/d/b;.setInput([F)V&quot;

I always got this error.


Code

Structure

  • Wrapper.java
  • native-lib.cpp
  • Wrapper.cpp

** <-> means communicate

Other Java Classes <-> Wrapper.java

Wrapper.java <-> native-lib.cpp

native-lib.cpp <-> Wrapper.cpp

Wrapper.cpp <-> Other C++ Classes


Wrapper.java

private static long wrapperAddr = 0; // initializes later

private tfModel model;
private native void nativeSetModel(long native_ptr, tfModel model);

public Wrapper(...){
    ...

    model = tfModel.create(tfModel.Model.MNIST, tfModel.Device.CPU, 1);
    nativeSetModel(wrapperAddr, model);
}

native-lib.cpp

extern &quot;C&quot; JNIEXPORT void JNICALL
Java_package_name_here_jni_Wrapper_nativeSetModel(JNIEnv *env,
                                                      jobject instance,
                                                      jlong native_ptr,
                                                      jobject model){
  
  auto wrapper = reinterpret_cast&lt;Wrapper *&gt;(native_ptr);
  
  wrapper-&gt;setModel(env, model);
}

Wrapper.cpp

void setModel(JNIEnv *env, jobject _model){
    env-&gt;GetJavaVM(&amp;translater::jvm);    
    jobject gmodel = env-&gt;NewGlobalRef(_model);    
    translater::model = gmodel;
  }

function A

...
translater::setInputTS(input1, 100);  // error starts here

...

translater.h / translater.cpp (function B)

class translater{
public:
    
    inline static JavaVM *jvm = nullptr;
    inline static jobject model = nullptr;
    
    // from: https://stackoverflow.com/a/30026231/8176989
    static bool GetJniEnv(JavaVM *vm, JNIEnv **env);  
    
    static void predictTS(std::vector&lt;float&gt; &amp;output);

    static void translater::setInputTS(float* input, int len) {
    
    
    JNIEnv *env;
    bool did_attach = GetJniEnv(jvm, &amp;env);

    if(did_attach){
        
        
        jclass clazz = env-&gt;GetObjectClass(model);
        jmethodID jid_input = env-&gt;GetMethodID(clazz, &quot;setInput&quot;, &quot;([F)V&quot;);  // Here is where error happens

    }

    ...    
};

tfModel.java

public abstract class tfModel{
...

    public void setInput(float[] array){
        if(inputIndex &lt; inputImageNum)
            setInput_Image(inputIndex, array);
        else
            setInput_Tensor(inputIndex - inputImageNum, array);
            
        ++inputIndex;
    }

}

How can I call
jmethodID jid_input = env-&gt;GetMethodID(clazz, &quot;setInput&quot;, &quot;([F)V&quot;);
correctly?

答案1

得分: 5

这是因为ProGuard会删除未使用的代码,有时可能会出错。
我添加了ProGuard的设置,一切正常运作。

链接:https://developer.android.com/studio/build/shrink-code#keep-code

.pro 文件

...
// 已添加
-keep abstract class package.name.here.module.tfModel{
    *;
}
英文:

It was because proguard removes unused code, which can be wrong sometimes.
I added the proguard settings, and everything works fine.

https://developer.android.com/studio/build/shrink-code#keep-code

.pro file

...
// added
-keep abstract class package.name.here.module.tfModel{
    *;
}

huangapple
  • 本文由 发表于 2020年3月4日 10:52:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/60518396.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定