英文:
Android JNI Error: NoSuchMethodError: no non-static method
问题
我尝试的内容如下。
- Java -> 调用 C++ 函数 A
- C++ 函数 A 调用 C++ 函数 B
- 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.
- Java -> Call C++ function A
- C++ function A calls C++ function B
- 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 "Lpackage/name/here/d/b;.setInput([F)V"
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 "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;
}
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<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"); // Here is where error happens
}
...
};
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;
}
}
How can I call
jmethodID jid_input = env->GetMethodID(clazz, "setInput", "([F)V");
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{
*;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论