Skip to content

Guard against IllegalStateException #1093

Open
hal-eisen-adfa wants to merge 2 commits intostagefrom
ADFA-3177-IllegalStateException
Open

Guard against IllegalStateException #1093
hal-eisen-adfa wants to merge 2 commits intostagefrom
ADFA-3177-IllegalStateException

Conversation

@hal-eisen-adfa
Copy link
Collaborator

BuildOutputFragment.clearOutput() was being called after the fragment is detached

The bottom sheet now clears the shared build-output state via its own ViewModel first

…put() is called after the fragment is detached
@hal-eisen-adfa hal-eisen-adfa requested a review from a team March 19, 2026 03:25
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Release Notes: Guard against IllegalStateException

  • Fixed IllegalStateException caused by calling BuildOutputFragment.clearOutput() after the fragment was detached.
  • Added attachment-state guard in BuildOutputFragment.clearOutput(): the fragment now avoids accessing the activity-scoped buildOutputViewModel unless the fragment is safely attached (isAdded && !isDetached).
  • Updated EditorBottomSheet.clearBuildOutput() to clear the persistent build-output state via the activity-scoped buildOutputViewModel before interacting with the fragment, and to only call fragment.clearOutput() when the fragment reference is present and attached.
  • Expanded KDoc for ShareableOutputFragment.clearOutput() to document that callers may invoke clearOutput() while a fragment is detached and to recommend guarding activity-scoped ViewModel access.

Risks / Best practices

  • Aligns with Android lifecycle best practices by checking fragment attachment state before accessing activity-scoped ViewModels, reducing lifecycle-related crashes.
  • Improves state management by clearing shared ViewModel state before touching fragment instances, lowering the chance of race conditions from asynchronous callbacks.
  • Minimal behavioral impact: change targets only the detachment edge case and preserves normal behavior when fragments are properly attached.

Walkthrough

Build output clearing now avoids touching activity-scoped ViewModel or calling fragment methods when the fragment is detached; KDoc for the shareable output interface documents this caller behavior.

Changes

Cohort / File(s) Summary
BuildOutput guard
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
clearOutput() now only calls buildOutputViewModel.clear() when the fragment is safely attached (isAdded && !isDetached).
EditorBottomSheet guard
app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
clearBuildOutput() clears activity-scoped buildOutputViewModel first, then only invokes fragment.clearOutput() if the fragment reference is non-null and attached (isAdded && !isDetached).
Docs / Interface KDoc
app/src/main/java/com/itsaky/androidide/fragments/output/ShareableOutputFragment.kt
Expanded KDoc for clearOutput() to state callers may invoke it while fragment is detached and implementations should guard against accessing activity-scoped ViewModels when `!isAdded

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • itsaky-adfa
  • Daniel-ADFA
  • jomen-adfa

Poem

🐰 A nibble, a hop, a cautious cheer,
I guard the ViewModel when fragments disappear.
No calls while detached, no tumble or fright,
Safe clears by moonbeam and morning light. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Guard against IllegalStateException' directly addresses the main objective of preventing an IllegalStateException that was occurring when clearOutput() was called on a detached fragment.
Description check ✅ Passed The description clearly explains the issue (clearOutput() called after fragment detachment) and the solution (clearing shared state via ViewModel first), which aligns with the changeset modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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-3177-IllegalStateException
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt (1)

433-442: Avoid duplicate shared-state clears on the attached-fragment path.

When attached, this now clears via buildOutputViewModel here and again inside BuildOutputFragment.clearOutput(). Consider using a single clear path to reduce redundant work.

♻️ Proposed simplification
 fun clearBuildOutput() {
-	// Always clear the persistent build output state via the bottom sheet's
-	// activity-scoped ViewModel.
-	buildOutputViewModel.clear()
-
-	// `clearOutput()` on the fragment may touch additional UI state, so only call it when
-	// the fragment is currently attached to an activity.
 	val fragment = pagerAdapter.buildOutputFragment
 	if (fragment != null && fragment.isAdded && !fragment.isDetached) {
 		fragment.clearOutput()
+		return
 	}
+	buildOutputViewModel.clear()
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt` around lines
433 - 442, The code currently always calls buildOutputViewModel.clear() and
then, when the fragment is attached, also calls
BuildOutputFragment.clearOutput(), causing duplicate clears; change the logic to
use a single clear path: if pagerAdapter.buildOutputFragment is attached
(fragment != null && fragment.isAdded && !fragment.isDetached) call
fragment.clearOutput() (which should handle UI and shared-state clearing),
otherwise call buildOutputViewModel.clear(); update references in
EditorBottomSheet to only clear the ViewModel when the fragment is not attached.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt`:
- Around line 433-442: The code currently always calls
buildOutputViewModel.clear() and then, when the fragment is attached, also calls
BuildOutputFragment.clearOutput(), causing duplicate clears; change the logic to
use a single clear path: if pagerAdapter.buildOutputFragment is attached
(fragment != null && fragment.isAdded && !fragment.isDetached) call
fragment.clearOutput() (which should handle UI and shared-state clearing),
otherwise call buildOutputViewModel.clear(); update references in
EditorBottomSheet to only clear the ViewModel when the fragment is not attached.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 70980486-3d8f-4499-9ccc-97c82e5aa28c

📥 Commits

Reviewing files that changed from the base of the PR and between bfd285b and 887b2d9.

📒 Files selected for processing (3)
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
  • app/src/main/java/com/itsaky/androidide/fragments/output/ShareableOutputFragment.kt
  • app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`:
- Around line 97-99: Remove the redundant call to buildOutputViewModel.clear()
in BuildOutputFragment to avoid racing with fresh append() activity from other
components (EditorBottomSheet already clears the shared BuildOutputViewModel and
calls fragment.clearOutput()); specifically, delete or disable the
buildOutputViewModel.clear() invocation inside the isAdded && !isDetached check
so the fragment no longer double-clears the shared state and conflicts with
EditorBottomSheet's clear logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b33cc994-5d9e-44fe-88c8-13d05acf274e

📥 Commits

Reviewing files that changed from the base of the PR and between 887b2d9 and 92abe7a.

📒 Files selected for processing (1)
  • app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt

Comment on lines +97 to +99
if (isAdded && !isDetached) {
buildOutputViewModel.clear()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid double-clearing shared build-output state here.

EditorBottomSheet already clears BuildOutputViewModel before calling fragment.clearOutput(). Clearing again in this fragment can race with fresh append() activity and wipe newly cached output/session state.

Suggested fix
 override fun clearOutput() {
-		// This fragment uses `activityViewModels()`, which relies on the fragment being attached.
-		// `clearOutput()` can be triggered from build/service callbacks even after the fragment
-		// has been detached, so we must guard before touching the activity-scoped ViewModel.
-		if (isAdded && !isDetached) {
-			buildOutputViewModel.clear()
-		}
+		// Shared build-output state is cleared by the caller-side ViewModel owner
+		// (e.g., EditorBottomSheet). Keep fragment clear local to UI/editor state.
 		super.clearOutput()
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isAdded && !isDetached) {
buildOutputViewModel.clear()
}
override fun clearOutput() {
// Shared build-output state is cleared by the caller-side ViewModel owner
// (e.g., EditorBottomSheet). Keep fragment clear local to UI/editor state.
super.clearOutput()
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`
around lines 97 - 99, Remove the redundant call to buildOutputViewModel.clear()
in BuildOutputFragment to avoid racing with fresh append() activity from other
components (EditorBottomSheet already clears the shared BuildOutputViewModel and
calls fragment.clearOutput()); specifically, delete or disable the
buildOutputViewModel.clear() invocation inside the isAdded && !isDetached check
so the fragment no longer double-clears the shared state and conflicts with
EditorBottomSheet's clear logic.

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.

2 participants