Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ internal class FabricUIManagerBinding : HybridClassBase() {

private external fun initHybrid()

private var animationBackendChoreographer: AnimationBackendChoreographer? = null

private external fun installFabricUIManager(
runtimeExecutor: RuntimeExecutor,
runtimeScheduler: RuntimeScheduler,
Expand Down Expand Up @@ -103,6 +105,7 @@ internal class FabricUIManagerBinding : HybridClassBase() {
animationBackendChoreographer.frameCallback = AnimationFrameCallback { frameTimeMs: Double ->
driveAnimationBackend(frameTimeMs)
}
this.animationBackendChoreographer = animationBackendChoreographer
setAnimationBackendChoreographer(animationBackendChoreographer)

installFabricUIManager(
Expand All @@ -118,6 +121,19 @@ internal class FabricUIManagerBinding : HybridClassBase() {
private external fun uninstallFabricUIManager()

fun unregister() {
// Stop driving the animation backend before tearing down the native binding.
// The choreographer's frame callback is registered with ReactChoreographer
// for the choreographer's lifetime and re-posts itself every frame, so it
// keeps invoking driveAnimationBackend even after uninstallFabricUIManager()
// has run. A late frame would then make a JNI call through this binding's
// freed native state (use-after-teardown). Pausing flips a memory-visible
// AtomicBoolean (unregister may run off the UI thread), so the UI-thread
// frame callback reliably no-ops afterwards.
animationBackendChoreographer?.let { choreographer ->
choreographer.pause()
choreographer.frameCallback = null
}
animationBackendChoreographer = null
uninstallFabricUIManager()
}

Expand Down
Loading