无效的JNI引用(从c++调用Java方法)
Invalid JNI reference (calling Java method from c++)
我有一个问题,从c++调用启用GPS定位。我用SWIG生成了JNI包装器。日志提示:
01-02 17:14:03.816: D/dalvikvm(6165): Trying to load lib /data/data/com.example.swig/lib/libcppinterface.so 0x44e7ebf0
01-02 17:14:03.976: D/dalvikvm(6165): Added shared lib /data/data/com.example.swig/lib/libcppinterface.so 0x44e7ebf0
01-02 17:14:04.886: W/dalvikvm(6165): JNI WARNING: 0x44e8bb48 is not a valid JNI reference
01-02 17:14:04.886: W/dalvikvm(6165): in Lcom/example/swig/cpplib/cppinterfaceJNI;.LocationSpotter_refresh (JLcom/example/swig/cpplib/LocationSpotter;)V (CallVoidMethodV)
01-02 17:14:04.886: I/dalvikvm(6165): "main" prio=5 tid=1 RUNNABLE
01-02 17:14:04.886: I/dalvikvm(6165): | group="main" sCount=0 dsCount=0 s=N obj=0x4001d8e0 self=0xccb0
01-02 17:14:04.886: I/dalvikvm(6165): | sysTid=6165 nice=0 sched=0/0 cgrp=default handle=-1345026008
01-02 17:14:04.886: I/dalvikvm(6165): | schedstat=( 226108400 549900071 66 )
01-02 17:14:04.886: I/dalvikvm(6165): at com.example.swig.cpplib.cppinterfaceJNI.LocationSpotter_refresh(Native Method)
01-02 17:14:04.896: I/dalvikvm(6165): at com.example.swig.cpplib.LocationSpotter.refresh(LocationSpotter.java:56)
01-02 17:14:04.896: I/dalvikvm(6165): at com.example.swig.MainActivity.onCreate(MainActivity.java:50)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
01-02 17:14:04.896: I/dalvikvm(6165): at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 17:14:04.896: I/dalvikvm(6165): at android.os.Looper.loop(Looper.java:123)
01-02 17:14:04.896: I/dalvikvm(6165): at android.app.ActivityThread.main(ActivityThread.java:4627)
01-02 17:14:04.896: I/dalvikvm(6165): at java.lang.reflect.Method.invokeNative(Native Method)
01-02 17:14:04.896: I/dalvikvm(6165): at java.lang.reflect.Method.invoke(Method.java:521)
01-02 17:14:04.896: I/dalvikvm(6165): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
01-02 17:14:04.896: I/dalvikvm(6165): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
01-02 17:14:04.896: I/dalvikvm(6165): at dalvik.system.NativeStart.main(Native Method)
01-02 17:14:04.906: E/dalvikvm(6165): VM aborting
我用这一行从Java触发调用:
LocationSpotter.getLocationSpotter().refresh();
getLocationSpotter()在c++中触发创建job对象(jSpotter)的代码:
// Retrieve the current JNIEnv* with the cached JVM
JNIEnv* env;
AndroidLocationSpotter::cachedJVM->AttachCurrentThread(&env, NULL);
jclass clazz = env->FindClass("com/example/swig/AndroidLocationSpotter");
jmethodID construct = env->GetMethodID(clazz, "<init>", "()V");
jSpotter = env->NewObject(clazz, construct);
和方法refresh()之后触发以下代码,导致应用程序崩溃:
// Retrieve the current JNIEnv* with the cached JVM
JNIEnv* env;
AndroidLocationSpotter::cachedJVM->AttachCurrentThread(&env, NULL);
jclass clazz = env->FindClass("com/example/swig/AndroidLocationSpotter");
jmethodID refresh = env->GetMethodID(clazz, "refresh", "()V");
env->CallVoidMethod(jSpotter, refresh); // The line where the crash happens
我还需要提到我在JNI_OnLoad函数中启动"cachedJVM"。希望有人能帮助我,谢谢。
编辑
工作代码:
// Retrieve the current JNIEnv* with the cached JVM
JNIEnv* env;
AndroidLocationSpotter::cachedJVM->AttachCurrentThread(&env, NULL);
jclass clazz = env->FindClass("com/example/swig/AndroidLocationSpotter");
jmethodID construct = env->GetMethodID(clazz, "<init>", "()V");
jSpotter = env->NewObject(clazz, construct);
jSpotter = env->NewGlobalRef(jSpotter);
您需要使用返回的jSpotter
引用创建一个新的全局引用。当前使用的引用是当前帧的本地引用,并且将超出作用域(可能在DetachCurrentThread()时)。
您需要调用env->NewGlobalRef(jSpotter)
或env->NewWeakGlobalRef(jSpotter)
(两者都有相应的free
函数)并使用返回的引用。
编辑
下面是一个正确的附加/分离处理的例子(假设您不需要线程进行进一步的Java操作): JNIEnv* env;
JavaVM* jvm = AndroidLocationSpotter::cachedJVM;
int attached = jvm->GetEnv((void *)&env, JNI_VERSION_1_4) == JNI_OK;
if (!attached) {
if (jvm->AttachCurrentThread((void *)&env, NULL) != JNI_OK) {
// Attach failed, handle error condition
return;
}
}
// Pushing a frame ensures proper cleanup of any local references you might generate
// in your JNI code, e.g. with NewLocalRef (optional)
if (env->PushLocalFrame(16) < 0) {
// Handle failed frame push error
}
else {
// example local reference generation: ref2 = env->NewLocalRef(ref);
//
// Perform your primary Java operations here
//
env->PopLocalFrame(NULL);
}
if (!attached) {
jvm->DetachCurrentThread();
}
相关文章:
- 调用 java 的回调() 时应用程序崩溃.由于 detatchThread 而获得运行时错误
- 尝试在 QT 项目中调用 Java 代码时未找到类异常
- Android:使用 c++ 中的 byte[] 参数调用 java 方法
- 如何在JNI中从线程内部调用JAVA方法
- 无法使用 JNI 从C++模块成功调用 Java 函数
- Android 无法从本机代码调用 Java 方法 JNI
- Android NDK - 引用 JNIEnv 从C++调用 Java
- 我可以通过CPP程序中的数据库调用调用Java程序
- 使用 JNI 从 cpp 调用 java 方法时出现异常
- 如何使JNI RegisterNatives调用Java函数具有C++实例范围
- 在Qt中从C ++调用Java方法
- 使用C 获取Java对象来调用Java方法
- 在QT中调用Java功能
- JNI:从C++调用JAVA方法,返回对象,引用和GC
- 从 Java 调用 c++,然后从相同的 c++ 方法调用 java 方法
- 安卓系统上的Qt蓝牙.通过抽象类上的jni调用java类
- 从Android NDK SIGSEGV调用Java方法
- 从C++调用 java 代码:exception java.lang.NoSuchMethodError
- Android NDK调用java方法表单cpp
- 从Qt C++调用Java函数