diff --git a/cmd/pad/impl_android.go b/cmd/pad/impl_android.go index 442cb5a..adf71ae 100644 --- a/cmd/pad/impl_android.go +++ b/cmd/pad/impl_android.go @@ -41,6 +41,15 @@ func impl_start() {} func handleEvent(e event.Event) { switch e := e.(type) { case app.AndroidViewEvent: + // View == 0 is Gio's DETACH signal (window.detach sends an empty + // AndroidViewEvent when the GioView is destroyed — e.g. the activity + // going away on a recents-wipe). There is nothing to register for a + // detached view; passing the null ref on would abort in JNI + // (GetObjectClass on null). A re-attach arrives as a fresh event + // with a live view. + if e.View == 0 { + return + } theJVM = (*C.JavaVM)(unsafe.Pointer(app.JavaVM())) RunInJVM(func(env *JNIEnv) { C.registerFragment(env, (C.jobject)(unsafe.Pointer(e.View))) diff --git a/cmd/pad/jni_android.c b/cmd/pad/jni_android.c index 3ca7b9f..df77efb 100644 --- a/cmd/pad/jni_android.c +++ b/cmd/pad/jni_android.c @@ -15,13 +15,17 @@ static jobject g_view = NULL; void registerFragment(JNIEnv *env, jobject view) { - if (view != NULL) { - if (g_view == NULL) { - g_view = (*env)->NewGlobalRef(env, view); - } else if (g_view != view) { - (*env)->DeleteGlobalRef(env, g_view); - g_view = (*env)->NewGlobalRef(env, view); - } + if (view == NULL) { + // Detach signal (Gio sends an empty AndroidViewEvent when the + // view is destroyed). The Go side already filters these; this + // guard keeps the JNI calls safe if one ever slips through. + return; + } + if (g_view == NULL) { + g_view = (*env)->NewGlobalRef(env, view); + } else if (g_view != view) { + (*env)->DeleteGlobalRef(env, g_view); + g_view = (*env)->NewGlobalRef(env, view); } jclass cls = (*env)->GetObjectClass(env, view); jmethodID mid = (*env)->GetMethodID(env, cls, "getContext", "()Landroid/content/Context;");