Skip to content

[Android] ScreenDummyLayoutHelper leaks Activity due to unreleased view references and missing lifecycle cleanup #3636

@l2hyunwoo

Description

@l2hyunwoo

Description

ScreenDummyLayoutHelper causes an Activity memory leak on Android because it holds strong references to dummy layout views (CoordinatorLayout, AppBarLayout, Toolbar, View) that are created with an Activity-based Context, but these references are never released when the Activity is destroyed.

The root cause is a combination of flawed lifecycle management:

  1. lateinit var prevents nullability — The view fields use lateinit var, making it impossible to set them to null for cleanup.
  2. Lifecycle listener is conditionally registered — In the constructor, addLifecycleEventListener is only called if maybeInitDummyLayoutWithHeader fails. If it succeeds (the common case), onHostDestroy is never invoked.
  3. Listener is removed prematurely in onHostResume — After successful initialization, removeLifecycleEventListener is called, preventing onHostDestroy from firing on subsequent Activity destruction.
  4. onHostDestroy does not release view references — Even when called, it only removes the lifecycle listener and does not null out the view fields.

This results in a reference chain: ScreenDummyLayoutHelperViewsContextThemeWrapperActivity, preventing the destroyed Activity (and its entire view hierarchy, resources, and window) from being garbage collected.

Expected behavior: When the host Activity is destroyed, all view references in ScreenDummyLayoutHelper should be released so the Activity can be garbage collected. On the next onHostResume, the helper should re-initialize with the new Activity's context.

Steps to reproduce

  1. Create a React Native app with react-native-screens using native stack navigation.
  2. Navigate through several screens to ensure ScreenDummyLayoutHelper is initialized (it measures header heights via dummy layout).
  3. Trigger an Activity recreation — this can happen via:
    • React Native dev reload (Fast Refresh / full reload)
    • Android configuration change (e.g., locale change, dark mode toggle) if Activity is recreated
    • Process death and restoration by the OS
  4. Use Android Studio Memory Profiler or LeakCanary to inspect retained objects.
  5. Observe that the previous Activity instance is retained in memory, held by ScreenDummyLayoutHelper's view fields (coordinatorLayout, appBarLayout, toolbar, dummyContentView).
  6. Repeat steps 3-5 to see the leak accumulate with each Activity recreation.

Snack or a link to a repository

(Will provide a minimal reproduction repository)

Screens version

4.23.0

React Native version

0.84.0

Platforms

Android

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Fabric (New Architecture)

Build type

Release mode

Device

Real device

Device model

Multiple Android devices (Android 12+)

Acknowledgements

Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    Missing reproThis issue need minimum repro scenarioPlatform: AndroidThis issue is specific to Android

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions