Repository navigation
A quick Back no longer crashes, and the crash report screen survives a crash - #113
Merged
Merged
Conversation
The navigation host in navigation-compose 2.8 does not act on Back right away. It queues the work for the next turn of the main thread and then animates the page it last drew on top. If the app changed the back stack in that gap (Play finishing its load and opening the Player, the book page's back arrow, a tab tap) the page was already gone and the host threw "Cannot transition entry that is not in the back stack", killing the app. Now every back stack change, from any caller, cancels a Back the host has not acted on yet. The change that cancelled it already moved the user, so nothing they asked for is lost. Navigation 2.10 reworked this path, but it needs Android Gradle plugin 9.1 and compileSdk 37, so the app-side guard is the fix for now. Instrumented tests reproduce the race on a real activity: the three race cases throw the production stack trace without the guard and pass with it, and plain Back and Back swipe still land on the Library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014XfNSbF1fe9aiDwGMCNLmj
Android runs the app's startup code in every process the app has, including the crash dialog's own ":acra" process. Since the 2.2.0 widget work, that startup code schedules widget work through WorkManager, which only exists in the main process. So after any crash the dialog's process threw "WorkManager is not initialized properly" and the crash report dialog died before the user could send anything. Startup now checks which process it is in and stops right after ACRA in any process other than the main one. Billing, sync, connectivity, the download cleanup, playback restore and the widget refresher all assumed the main process, so none of them start in the crash process now. The app's dependencies are injected lazily, so the crash process does not even build them. AppProcessTest pins the process check: the main process counts, the crash process and any other side process do not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014XfNSbF1fe9aiDwGMCNLmj
…104) Review follow ups for the back race guard. BackGestureRaceTest now checks that a plain Back and a plain Back swipe finish the page change, not just pick the right route: the Library is RESUMED, it is the only page the host still draws, and the book page was torn down. The swipe race test now asserts where the user ends up, and a new variant pops the page while the swipe is already in progress. BackRaceGuard explains that its listener also fires at registration and after a configuration change with nothing pending, which is harmless. The version catalog marks activityCompose and navigationCompose bumps as gated on BackGestureRaceTest, because the guard relies on the test-only dispatchOnBackCancelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014XfNSbF1fe9aiDwGMCNLmj
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #104.
What changes for the listener
A quick Back while the app changes pages no longer crashes (#104). In navigation-compose 2.8.5, a Back (key or swipe) is queued to the next main thread turn and reads the page list as of the last draw. If the app changes pages in that gap (the book page's back arrow, Play opening the Player, a tab tap), the queued work animates a page that's already gone and throws "Cannot transition entry that is not in the back stack".
BackRaceGuardcancels any Back the host hasn't acted on yet whenever the destination changes, so the stale work never runs. Upgrading to navigation 2.10 is the real upstream fix, but it needs AGP 9.1 and compileSdk 37, so that waits. 2.9.x still has the race.The crash report screen survives a crash again. This is a 2.2.0 regression from the widget work (#110, #111).
NineLivesApp.onCreateran all main process startup inside ACRA's:acracrash dialog process, and the widget refresher's WorkManager call threw there and took the dialog down. Startup now runs only in the main process, and the injected fields are lazy so the crash process never builds them.Choices worth knowing
dispatchOnBackCancelled(), which is public but marked@VisibleForTesting. The version catalog now saysBackGestureRaceTestmust pass on a device before activity or navigation gets bumped.Evidence
BackGestureRaceTest: 7 of 7 pass. Without the guard, 3 fail with the production stack.🤖 Generated with Claude Code
https://claude.ai/code/session_014XfNSbF1fe9aiDwGMCNLmj