自定义Gluon Attach插件中Java Runnable的JNI传递调用异常
自定义Gluon Attach插件中Runnable对象跨JNI层传递调用问题
背景
开发自定义Gluon Attach插件时,尝试将Java Runnable对象作为native方法showSaveAlert3的参数从Java层传递到JNI层,Native侧调用该Runnable时持续报错:
JNI DETECTED ERROR IN APPLICATION: JNI ERROR (app bug): jobject is an invalid JNI transition frame reference: 0x8000000000000008
代码概览
Java类1(AndroidAlertDialogService)
package com.gluonhq.attachextended.alertdialog.impl; import com.gluonhq.attachextended.alertdialog.AlertDialogService; public class AndroidAlertDialogService implements AlertDialogService { static { System.loadLibrary("alertdialog"); } @Override public void showSaveAlert(String title, String content, Runnable r) { showSaveAlert3(title, content, r); } private native static void showSaveAlert3(String title, String content, Runnable r); }
JNI代码(alertdialog.c)
#include "util.h" static jclass jAlertDialogServiceClass; static jobject jDalvikAlertDialogService; static jmethodID jAlertDialogServiceShowSaveAlert3Method; static void initializeAlertDialogDalvikHandles() { jAlertDialogServiceClass = GET_REGISTER_DALVIK_CLASS(jAlertDialogServiceClass, "com/gluonhq/helloandroid/DalvikAlertDialogService"); ATTACH_DALVIK(); jmethodID jAlertDialogServiceInitMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jAlertDialogServiceClass, "<init>", "(Landroid/app/Activity;)V"); jAlertDialogServiceShowSaveAlert3Method = (*dalvikEnv)->GetMethodID(dalvikEnv, jAlertDialogServiceClass, "showSaveAlert3", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Runnable;)V"); jobject jActivity = substrateGetActivity(); jobject jObj = (*dalvikEnv)->NewObject(dalvikEnv, jAlertDialogServiceClass, jAlertDialogServiceInitMethod, jActivity); jDalvikAlertDialogService = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jObj); DETACH_DALVIK(); } ////////////////////////// // From Graal to native // ////////////////////////// JNIEXPORT jint JNICALL JNI_OnLoad_alertdialog(JavaVM *vm, void *reserved) { JNIEnv* graalEnv; ATTACH_LOG_INFO("JNI_OnLoad_alertdialog called"); #ifdef JNI_VERSION_1_8 if ((*vm)->GetEnv(vm, (void **)&graalEnv, JNI_VERSION_1_8) != JNI_OK) { ATTACH_LOG_WARNING("Error initializing native AlertDialog from OnLoad"); return JNI_FALSE; } ATTACH_LOG_FINE("[AlertDialog Service] Initializing native AlertDialog from OnLoad"); initializeAlertDialogDalvikHandles(); return JNI_VERSION_1_8; #else #error Error: Java 8+ SDK is required to compile Attach #endif } // from Java to Android JNIEXPORT void JNICALL Java_com_gluonhq_attachextended_alertdialog_impl_AndroidAlertDialogService_showSaveAlert3 (JNIEnv *env, jclass jClass, jstring jtitle, jstring jcontent, jobject jr) { const char *titleChars = (*env)->GetStringUTFChars(env, jtitle, NULL); const char *contentChars = (*env)->GetStringUTFChars(env, jcontent, NULL); ATTACH_DALVIK(); jstring jTitleString = (*dalvikEnv)->NewStringUTF(dalvikEnv, titleChars); jstring jContentString = (*dalvikEnv)->NewStringUTF(dalvikEnv, contentChars); jobject globalRunnable = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jr); jclass rClass = (*dalvikEnv)->GetObjectClass(dalvikEnv, globalRunnable); jmethodID midMyCustomMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, rClass, "run", "()V"); (*dalvikEnv)->CallVoidMethod(dalvikEnv, jDalvikAlertDialogService, jAlertDialogServiceShowSaveAlert3Method, jTitleString, jContentString, midMyCustomMethod); DETACH_DALVIK(); (*env)->ReleaseStringUTFChars(env, jtitle, titleChars); (*env)->ReleaseStringUTFChars(env, jcontent, contentChars); }
Java类2(DalvikAlertDialogService)
package com.gluonhq.helloandroid; import android.app.AlertDialog; import android.content.DialogInterface; import android.app.Activity; public class DalvikAlertDialogService { private final Activity activity; public DalvikAlertDialogService(Activity activity) { this.activity = activity; } public void showSaveAlert3(String title, String content, Runnable r) { activity.runOnUiThread(() -> { if (!activity.isFinishing()) { AlertDialog.Builder dialog = new AlertDialog.Builder(activity); dialog.setCancelable(false); dialog.setTitle(title); dialog.setMessage(content); dialog.setPositiveButton("Ok", (DialogInterface dialog1, int id) -> { dialog1.dismiss(); r.run(); }); AlertDialog alert = dialog.create(); alert.show(); } }); } }
已尝试方案
- 使用
NewGlobalRef创建Runnable对象的持久引用后再调用其run方法。 - 检查Dalvik环境(
dalvikEnv)的有效性。 - 查阅Gluon Attach现有插件(如DisplayService、StorageService)源码,但这些示例主要关注字符串、基本类型或数组的传递,未涉及
Runnable这类复杂Java对象。
问题说明
尽管做了上述尝试,仍无法调用Runnable的run()方法,jobject引用在JNI环境中似乎失效,导致上述错误。
疑问
- 在此场景下,将Java
Runnable对象传递到JNI并调用其run()方法的正确方式是什么? - 处理Gluon Attach中的
Runnable对象是否有遗漏的特定步骤? - 该问题是否与Dalvik环境中引用管理(
NewGlobalRef、Detach等)不当有关?
内容的提问来源于stack exchange,提问作者CTO - Abid Maqbool
相关产品推荐
相关产品推荐

