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:
Elias Naur
2020-06-13 16:09:33 +02:00
parent f36674ddb3
commit 8688ed95c2
4 changed files with 60 additions and 57 deletions
+28 -14
View File
@@ -17,18 +17,32 @@ func AppContext() uintptr {
return window.AppContext()
}
// androidDriver is an interface that allows the Window's run method
// to call the RegisterFragment method of the Android window driver.
type androidDriver interface {
RegisterFragment(string)
}
// RegisterFragment constructs a Java instance of the specified class
// and registers it as a Fragment in the Context in which the View was
// created.
func (w *Window) RegisterFragment(del string) {
w.driverDo(func() {
d := w.driver.(androidDriver)
d.RegisterFragment(del)
})
// Do invokes the function with a JNI jobject handle to the underlying
// Android View. The function is invoked on the main thread, and the
// handle is invalidated after the function returns.
//
// Note: Do may deadlock if called from the same goroutine that receives from
// Events.
func (w *Window) Do(f func(view uintptr)) {
type androidDriver interface {
Do(f func(view uintptr)) bool
}
success := make(chan bool)
for {
driver := make(chan androidDriver, 1)
// two-stage process: first wait for a valid driver...
w.driverDo(func() {
driver <- w.driver.(androidDriver)
})
// .. then run the function on the main thread using the
// driver. The driver Do method returns false if the
// view was invalidated while switching to the main thread.
window.RunOnMain(func() {
d := <-driver
success <- d.Do(f)
})
if <-success {
break
}
}
}