Skip to content

Commit ea5882b

Browse files
lazergmeta-codesync[bot]
authored andcommitted
Don't resume the new context without an Activity after a reload on Android (#59474)
Summary: If the Activity is destroyed while a reload is still running, `ReactHostImpl` finishes the reload by calling `moveToOnHostResume(reactContext, currentActivity)` with `currentActivity` already null. The new context gets `onHostResume(null)` and the lifecycle state becomes `RESUMED`, so when the app is reopened `onHostResume(activity)` returns early and `getCurrentActivity()` stays null until the next pause/resume. That's what makes `PermissionsAndroid.request()` reject with `E_INVALID_ACTIVITY` (and likely the `Alert` error in #46201). The reload branch now only resumes the context when there is an Activity. Otherwise it falls through to the normal path, and the next `onHostResume(activity)` resumes the context with the right Activity. Fixes #59473 ## Changelog: [ANDROID] [FIXED] - Fix `getCurrentActivity()` staying null after the Activity is destroyed during a reload Pull Request resolved: #59474 Test Plan: Added `ReactHostTest.testActivityDestroyedDuringReload`. It queues background work so the Activity can be paused and destroyed before the reload finishes, then resumes a new Activity and checks the new context gets it. On `main` it fails (state is `RESUMED` and the context only got `onHostResume(null)`), and it passes with this change. `./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest` passes and ktfmt is clean. I didn't run the reproducer on a device. Reviewed By: christophpurrer Differential Revision: D127564742 Pulled By: javache fbshipit-source-id: 37a80ed86e799473bfc6ed251f60c5ae58506772
1 parent 9c8a368 commit ea5882b

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ public class ReactHostImpl(
11091109
* Native is reloading, it seems reasonable to assume that: (1) We must have navigated to a
11101110
* React Native screen in the past, or (2) We must be on a React Native screen.
11111111
*/
1112-
if (isReloading && !isManagerResumed) {
1112+
if (isReloading && !isManagerResumed && currentActivity != null) {
11131113
reactLifecycleStateManager.moveToOnHostResume(reactContext, currentActivity)
11141114
} else {
11151115
/**

‎packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/ReactHostTest.kt‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,38 @@ class ReactHostTest {
168168
reactHost.onHostDestroy(activityController.get())
169169
assertThat(reactHost.lifecycleState).isEqualTo(LifecycleState.BEFORE_CREATE)
170170
}
171+
172+
@Test
173+
fun testActivityDestroyedDuringReload() {
174+
val bgTasks = ArrayDeque<Runnable>()
175+
reactHost =
176+
spy(
177+
ReactHostImpl(
178+
activityController.get().application,
179+
reactHostDelegate,
180+
mock(),
181+
{ bgTasks.add(it) },
182+
Task.IMMEDIATE_EXECUTOR,
183+
false /* allowPackagerServerAccess */,
184+
false /* useDevSupport */,
185+
),
186+
)
187+
doReturn(null).whenever(reactHost).getOrCreateReactHostInspectorTarget()
188+
doNothing().whenever(reactHost).unregisterInstanceFromInspector(any())
189+
190+
reactHost.start()
191+
while (bgTasks.isNotEmpty()) bgTasks.removeFirst().run()
192+
reactHost.onHostResume(activityController.get())
193+
194+
reactHost.reload("Reload from testing infra")
195+
reactHost.onHostPause(activityController.get())
196+
reactHost.onHostDestroy(activityController.get())
197+
while (bgTasks.isNotEmpty()) bgTasks.removeFirst().run()
198+
assertThat(reactHost.lifecycleState).isEqualTo(LifecycleState.BEFORE_CREATE)
199+
200+
val newActivity = Robolectric.buildActivity(Activity::class.java).create().start().resume()
201+
reactHost.onHostResume(newActivity.get())
202+
val newReactContext = mockedBridgelessReactContextCtor.constructed().last()
203+
verify(newReactContext).onHostResume(newActivity.get())
204+
}
171205
}

0 commit comments

Comments
 (0)