I'm having a problem with a call to enable the GPS localization from c++. I generated the JNI wrappers with SWIG. The logcat says :
01-02 17:14:03.816: D/dalvikvm(6165): Trying to load lib /data/data/com.example.swig/lib/libcppinterface.so 0x44e7ebf001-02 17:14:03.976: D/dalvikvm(6165): Added shared lib /data/data/com.example.swig/lib/libcppinterface.so 0x44e7ebf001-02 17:14:04.886: W/dalvikvm(6165): JNI WARNING: 0x44e8bb48 is not a valid JNI reference01-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 RUNNABLE01-02 17:14:04.886: I/dalvikvm(6165): | group="main" sCount=0 dsCount=0 s=N obj=0x4001d8e0 self=0xccb001-02 17:14:04.886: I/dalvikvm(6165): | sysTid=6165 nice=0 sched=0/0 cgrp=default handle=-134502600801-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 abortingI trigger the call from Java with this line :
LocationSpotter.getLocationSpotter().refresh();getLocationSpotter() triggers in c++ this code which creates a jobject (jSpotter) :
// Retrieve the current JNIEnv* with the cached JVMJNIEnv* 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);and after the method refresh() triggers this code which makes the application crash :
// Retrieve the current JNIEnv* with the cached JVMJNIEnv* 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 happensI also need to mention that I initiate "cachedJVM" in the JNI_OnLoad function. Hope someone could help me on this, thanks
EDIT
Working code :
// Retrieve the current JNIEnv* with the cached JVMJNIEnv* 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);1 Answer1
You need to create a new global reference using the returnedjSpotter reference. The reference you are currently using is local to your current frame, and will go out of scope (probably when you DetachCurrentThread()).
You need to callenv->NewGlobalRef(jSpotter) orenv->NewWeakGlobalRef(jSpotter) (both of which have correspondingfree functions) and use the reference returned.
EDIT
Here's an example of proper attach/detach handling (assuming you don't need the thread for further Java operations):
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(); }2 Comments
env->NewGlobalRef(jSpotter); in my code, I had another problem when running the app on my device (apparently because of ICS). You should instead writejSpotter = env->NewGlobalRef(jSpotter);. Check the edit to see thoses changesExplore related questions
See similar questions with these tags.
