Skip to content

ADFA-3472: Guard BuildOutputFragment access when detached#1415

Merged
hal-eisen-adfa merged 4 commits into
stagefrom
ADFA-3472-buildoutputfragment-not-attached
Jun 26, 2026
Merged

ADFA-3472: Guard BuildOutputFragment access when detached#1415
hal-eisen-adfa merged 4 commits into
stagefrom
ADFA-3472-buildoutputfragment-not-attached

Conversation

@fryanpan

@fryanpan fryanpan commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Jira Ticket: https://appdevforall.atlassian.net/browse/ADFA-3472
Sentry Issue: https://appdevforall-inc-9p.sentry.io/issues/APPDEVFORALL-N4

Question

Looks like this file is part of AndroidIDE -- do we make changes here or upstream?

Reproduction Details

BuildOutputFragment holds buildOutputViewModel via by activityViewModels(). When clearOutput() / getShareableContent() run on a detached fragment, forcing that lazy delegate calls requireActivity(), which throws IllegalStateException: … not attached to an activity.

Stack Trace

IllegalStateException: Fragment BuildOutputFragment{…} not attached to an activity.
  at androidx.fragment.app.Fragment.requireActivity(Fragment.java:1005)
  at …BuildOutputFragment$special$$inlined$activityViewModels$default$1.invoke(FragmentViewModelLazy.kt:176)
  at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:49)
  (entered via clearOutput() / getShareableContent())

User Steps

User steps leading up to crash, based on Sentry breadcrumbs:

  • A build is running; the user rapidly switches/swipes between the bottom output tabs (Build Output → App Log → IDE Log → Diagnostics → Debugger → Git). BuildOutputFragment goes through save-state → stopped → view destroyed → detached, and an incoming build-output update then calls clearOutput() on the now-detached fragment → crash.

Was able to reproduce in a unit test?

Yes.
BuildOutputFragmentDetachedTest (:app, Robolectric) constructs a never-attached fragment (isAdded == false) and calls each method. Baseline: both FAIL with IllegalStateException at requireActivity via the activityViewModels delegate; branch: both pass.

What Was Fixed

if (!isAdded || activity == null) return guard in clearOutput() / getShareableContent() (returns "" for the latter) before touching the activity-scoped view model.

Testing

:app:testV8DebugUnitTest → 2/2 green (red on baseline). Local CodeRabbit review: no findings. Reviewer note (local): the activity == null clause is redundant with !isAdded, and EditorBottomSheet's takeIf { it.isAdded } is now belt-and-suspenders — harmless. viewLifecycleOwner is NOT the right alternative here (the precondition is isAdded, which it doesn't capture).


Fixes APPDEVFORALL-N4

@fryanpan fryanpan marked this pull request as ready for review June 19, 2026 11:17
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f86ef5e9-6091-432c-9cd7-d8703b168b16

📥 Commits

Reviewing files that changed from the base of the PR and between ff679f4 and 2eba265.

📒 Files selected for processing (3)
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
  • app/src/test/java/com/itsaky/androidide/fragments/output/BuildOutputFragmentDetachedTest.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/test/java/com/itsaky/androidide/fragments/output/BuildOutputFragmentDetachedTest.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt

📝 Walkthrough
  • Fixed a crash in BuildOutputFragment when it is detached from its activity by guarding access to the activity-scoped buildOutputViewModel in clearOutput() and getShareableContent().

  • clearOutput() now returns early when the fragment is not attached, preventing requireActivity()-backed access from throwing IllegalStateException.

  • getShareableContent() now returns an empty string when detached instead of crashing.

  • EditorBottomSheet.clearBuildOutput() now only calls clearOutput() when the BuildOutputFragment is actually added to the fragment manager.

  • Added a Robolectric regression test covering detached-fragment behavior for both clearOutput() and getShareableContent().

  • Risk / best-practice note: the new isAdded/activity == null guards prevent the crash, but callers must still ensure fragment lifecycle state is valid before invoking output updates; otherwise output may be silently skipped when detached.

Walkthrough

BuildOutputFragment.clearOutput() and getShareableContent() now return early when the fragment is detached. EditorBottomSheet.clearBuildOutput() now checks attachment before clearing output. A regression test covers the detached fragment behavior.

Changes

Detached Fragment Crash Fix

Layer / File(s) Summary
Detachment guards in BuildOutputFragment and EditorBottomSheet
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt, app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
clearOutput() and getShareableContent() return early when `!isAdded
Detached fragment regression test
app/src/test/java/com/itsaky/androidide/fragments/output/BuildOutputFragmentDetachedTest.kt
New Robolectric test coverage exercises detached BuildOutputFragment behavior for clearOutput() and getShareableContent().

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • jatezzz
  • Daniel-ADFA
  • itsaky-adfa

Poem

🐇 I hopped to a fragment that wandered away,
Checked isAdded first, then I went on my way.
No crash in the dusk, just a quiet retreat,
An empty string now, and the test feels complete.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: preventing detached BuildOutputFragment access.
Description check ✅ Passed The description is directly related to the crash fix and regression test changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-3472-buildoutputfragment-not-attached

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

fryanpan and others added 3 commits June 19, 2026 09:58
Sentry APPDEVFORALL-N4. Skip activityViewModels access when the fragment
is detached; guard the caller with isAdded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reproduces the Sentry IllegalStateException ('not attached to an activity')
thrown when clearOutput()/getShareableContent() force the activityViewModels
lazy delegate (-> requireActivity()) on a detached fragment. RED on the
pre-fix baseline (4d9b100), GREEN with the isAdded/activity guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@fryanpan fryanpan force-pushed the ADFA-3472-buildoutputfragment-not-attached branch from 64ac5df to e6941b4 Compare June 19, 2026 16:58
@hal-eisen-adfa hal-eisen-adfa merged commit 4348978 into stage Jun 26, 2026
2 checks passed
@hal-eisen-adfa hal-eisen-adfa deleted the ADFA-3472-buildoutputfragment-not-attached branch June 26, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants