mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
app/internal/window: [Android] replace RegisterFragment with Do
Do is a function for accessing the underlying Android View in a safe context, the main thread. Do is - more general than RegisterFragment and may be expanded to other platforms - simpler to implement (from the Gio side) and as a bonus, the Do implementation avoids a race condition where a call to RegisterFragment during an Activity re-create would be ignored. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -191,31 +191,6 @@ public final class GioView extends SurfaceView implements Choreographer.FrameCal
|
||||
return onBack(nhandle);
|
||||
}
|
||||
|
||||
void registerFragment(String del) {
|
||||
final Class cls;
|
||||
try {
|
||||
cls = getContext().getClassLoader().loadClass(del);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("RegisterFragment: fragment class not found: " + e.getMessage());
|
||||
}
|
||||
|
||||
final Fragment frag;
|
||||
try {
|
||||
frag = (Fragment)cls.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException | ExceptionInInitializerError | SecurityException | ClassCastException e) {
|
||||
throw new RuntimeException("RegisterFragment: error instantiating fragment: " + e.getMessage());
|
||||
}
|
||||
final FragmentManager fm;
|
||||
try {
|
||||
fm = ((Activity)getContext()).getFragmentManager();
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException("RegisterFragment: cannot get fragment manager from View Context: " + e.getMessage());
|
||||
}
|
||||
FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.add(frag, del);
|
||||
ft.commitNow();
|
||||
}
|
||||
|
||||
static private native long onCreateView(GioView view);
|
||||
static private native void onDestroyView(long handle);
|
||||
static private native void onStartView(long handle);
|
||||
|
||||
@@ -80,7 +80,6 @@ type window struct {
|
||||
mshowTextInput C.jmethodID
|
||||
mhideTextInput C.jmethodID
|
||||
mpostFrameCallback C.jmethodID
|
||||
mRegisterFragment C.jmethodID
|
||||
}
|
||||
|
||||
type jvalue uint64 // The largest JNI type fits in 64 bits.
|
||||
@@ -193,7 +192,6 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
|
||||
mshowTextInput: getMethodID(env, class, "showTextInput", "()V"),
|
||||
mhideTextInput: getMethodID(env, class, "hideTextInput", "()V"),
|
||||
mpostFrameCallback: getMethodID(env, class, "postFrameCallback", "()V"),
|
||||
mRegisterFragment: getMethodID(env, class, "registerFragment", "(Ljava/lang/String;)V"),
|
||||
}
|
||||
wopts := <-mainWindow.out
|
||||
w.callbacks = wopts.window
|
||||
@@ -416,7 +414,6 @@ func runInJVM(jvm *C.JavaVM, f func(env *C.JNIEnv)) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
var env *C.JNIEnv
|
||||
var detach bool
|
||||
if res := C.gio_jni_GetEnv(jvm, &env, C.JNI_VERSION_1_6); res != C.JNI_OK {
|
||||
if res != C.JNI_EDETACHED {
|
||||
panic(fmt.Errorf("JNI GetEnv failed with error %d", res))
|
||||
@@ -424,14 +421,9 @@ func runInJVM(jvm *C.JavaVM, f func(env *C.JNIEnv)) {
|
||||
if C.gio_jni_AttachCurrentThread(jvm, &env, nil) != C.JNI_OK {
|
||||
panic(errors.New("runInJVM: AttachCurrentThread failed"))
|
||||
}
|
||||
detach = true
|
||||
defer C.gio_jni_DetachCurrentThread(jvm)
|
||||
}
|
||||
|
||||
if detach {
|
||||
defer func() {
|
||||
C.gio_jni_DetachCurrentThread(jvm)
|
||||
}()
|
||||
}
|
||||
f(env)
|
||||
}
|
||||
|
||||
@@ -537,11 +529,21 @@ func javaString(env *C.JNIEnv, str string) C.jstring {
|
||||
return C.gio_jni_NewString(env, (*C.jchar)(unsafe.Pointer(&utf16Chars[0])), C.int(len(utf16Chars)))
|
||||
}
|
||||
|
||||
func (w *window) RegisterFragment(del string) {
|
||||
w.runOnMain(func(env *C.JNIEnv) {
|
||||
jstr := javaString(env, del)
|
||||
callVoidMethod(env, w.view, w.mRegisterFragment, jvalue(jstr))
|
||||
// Do invokes the function with a global JNI handle to the view. If
|
||||
// the view is destroyed, Do returns false and does not invoke the
|
||||
// function.
|
||||
//
|
||||
// NOTE: Do must be invoked on the Android main thread.
|
||||
func (w *window) Do(f func(view uintptr)) bool {
|
||||
if w.view == 0 {
|
||||
return false
|
||||
}
|
||||
runInJVM(javaVM(), func(env *C.JNIEnv) {
|
||||
view := C.gio_jni_NewGlobalRef(env, w.view)
|
||||
defer C.gio_jni_DeleteGlobalRef(env, view)
|
||||
f(uintptr(view))
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
func varArgs(args []jvalue) *C.jvalue {
|
||||
@@ -645,6 +647,14 @@ func (w *window) ReadClipboard() {
|
||||
})
|
||||
}
|
||||
|
||||
// RunOnMain is the exported version of runOnMain without a JNI
|
||||
// environement.
|
||||
func RunOnMain(f func()) {
|
||||
runOnMain(func(_ *C.JNIEnv) {
|
||||
f()
|
||||
})
|
||||
}
|
||||
|
||||
// runOnMain runs a function on the Java main thread.
|
||||
func runOnMain(f func(env *C.JNIEnv)) {
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user