Skip to content
Open
Show file tree
Hide file tree
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
13 changes: 12 additions & 1 deletion android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,8 @@ open class ScreenFragment :
override fun onDestroy() {
super.onDestroy()
val container = screen.container
if (container == null || !container.hasScreen(this.screen.fragmentWrapper)) {
val isScreenDismissed = container == null || !container.hasScreen(this.screen.fragmentWrapper)
if (isScreenDismissed) {
// we only send dismissed even when the screen has been removed from its container
val screenContext = screen.context
if (screenContext is ReactContext) {
Expand All @@ -325,6 +326,16 @@ open class ScreenFragment :
.getEventDispatcherForReactTag(screenContext, screen.id)
?.dispatchEvent(ScreenDismissedEvent(surfaceId, screen.id))
}
// Break the Screen->fragmentWrapper retain cycle so Fabric's
// SurfaceMountingManager.mTagToViewState doesn't keep the destroyed
// ScreenFragment alive. Gated on isScreenDismissed since onDestroy
// can also fire in non-dismissal lifecycle paths where the wrapper
// must remain reachable. Identity guard avoids clobbering a wrapper
// that has been re-assigned to a different fragment.
// See: https://github.com/software-mansion/react-native-screens/issues/3755
if (this.screen.fragmentWrapper === this) {
this.screen.fragmentWrapper = null
}
}
childScreenContainers.clear()
}
Expand Down
13 changes: 13 additions & 0 deletions android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ open class ScreenViewManager :
view.onFinalizePropsUpdate()
}

// Belt-and-braces fragmentWrapper cleanup, in case Fabric drops the view
// without ScreenFragment.onDestroy firing on schedule. Breaks the
// Screen->fragmentWrapper retain cycle so SurfaceMountingManager doesn't
// keep the destroyed fragment alive. Guarded so we only null when no
// fragment is currently attached.
// See: https://github.com/software-mansion/react-native-screens/issues/3755
override fun onDropViewInstance(view: Screen) {
if (view.fragmentWrapper?.fragment?.isAdded != true) {
view.fragmentWrapper = null
}
super.onDropViewInstance(view)
}

fun setActivityState(
view: Screen,
activityState: Int,
Expand Down