Repository navigation
fix(android): Nav3 multi-Activity support now plays nicely with nav roots that don't have a SentryNavEffect - #6480
Open
0xadam-brown wants to merge 1 commit into
Open
0xadam-brown wants to merge 1 commit into
0xadam-brown wants to merge 1 commit into
Conversation
5 of 9 tasks
📲 Install BuildsAndroid
|
This was referenced Nov 6, 2026
0xadam-brown
marked this pull request as ready for review
November 6, 2026 12:31
5 of 9 tasks
This branch has not been deployed
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.
PR Stack (Nav3 Lifecycle)
📜 Description
Part 3 of our Nav3 support for multi-Activity and multi-Fragment apps. In part 1 we provided the basic mechanism for coordinating multiple SentryNavEffects; and in part 2 we adapted our approach to the quirks of ViewPager2 and other oddball Fragment lifecycles.
Both of those PR stacks assumed that any Activities or Fragments that had a SentryNavEffect would only launch other Activities or Fragments that also had SentryNavEffects. This PR stack handles situations where Activities or Fragments with SentryNavEffects interact with Activities or Fragments without them.
Background.
A nav root is an Activity or Fragment that owns a nav back stack and passes it to a SentryNavEffect. (An Activity or Fragment that doesn't have a SentryNavEffect is called a non-candidate root.) When the user navigates to a new destination, SentryNavEffect records the screen name, the nav context and one nav transaction.
Each nav root has its own SentryNavEffect instance and all instances write to the same
IScopewith a single transaction slot. Auto-instrumented spans (HTTP, database, and so on) attach to whatever transaction is in that slot. With multi-Activity or multi-Fragment apps, several nav roots can be alive at the same time (e.g., an Activity covered by another Activity, or neighboring ViewPager2 pages), meaning SentryNavEffect is subject to the classical headaches of shared global state.NavLeaseCoordinatorwas (and remains) our answer to those headaches. It prevents multiple, simultaneously active SentryNavEffects from clobbering each others' updates via a nav lease, viz., by only allowing the nav root holding the lease to write nav data to the IScope or bind to its transaction slot. When the lease is transferred, the old holder's data is removed and its transaction is unbound but left running.The gaps in our existing implementation
Our original lease model left three gaps that could cause stale nav data to be left on the shared IScope as the user moved around the host app:
SentryNavEffectui.loadtransaction†ui.loadbinds in preference to the nav transaction, as it does with Nav2 (#6484)Unchanged
sentry-android-coreisn't modified. #6484 works aroundActivityLifecycleIntegration's callback timing instead.Known limitations
All limitations are documented in the package README.
[1] A
ui.actionfrom the gesture that caused a return can still block the nav transaction.[2] We rely on the pausing of the nav root holding the lease in order to remove its nav data + transaction from the shared IScope in situations where a non-candidate root covers the leaseholder. If the nav root can be covered without being paused, we won't know about it and we won't remove its (arguably stale) data from the IScope. That happens with Fragment dialogs, Compose dialogs, and bottom sheets.
[3] Below API 29, an Activity opened from a nav root still doesn't get its
ui.loadtransaction bound and we bind the nav transaction instead. Theui.loadtransaction is created and sent in both cases, but it's not bound to the transaction for pre-API 29 devices, and so it won't be the parent of any HTTP, SQLite or other ambient spans (the nav transaction will be instead).Note: Updating pre-API 29 devices to match requires modifying
ActivityLifecycleIntegration. I haven't included that change here because it would have impacts beyond Nav3. We could do it in a follow-up if folks care to. Nicely, it'd let us simplify the API 29+ approach implemented here, as well.💡 Motivation and Context
Absent this PR stack, apps that mix Nav3 with plain Activities, ViewPager2 or other Activities could see stale nav data or spans attributed to the wrong screen. They could also lose spans produced when the user returned to a screen, and see
ui.loadbehavior that differs from Nav2.See the originating Slack convo here.
addresses: JAVA-823 and JAVA-785
💚 How did you test it?
See the individual PRs.
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps
#skip-changelog
Merge the stack PRs bottom to top using merge commits, then squash-merge this PR.