fix(service): resolve UninitializedPropertyAccessException in onGetSession#3861
Conversation
📝 WalkthroughWalkthroughThis PR addresses a race condition where ChangesMediaSession Null-Safety Initialization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt (2)
910-910: 💤 Low valueConsider simplifying the player assignment pattern.
The current pattern
mediaSession?.let { (it as MediaSession).player = newPlayer }requires a downcast fromMediaLibrarySessiontoMediaSessionto access theplayerproperty setter. While this is safe (MediaLibrarySession extends MediaSession) and already wrapped in try-catch blocks, the cast is somewhat awkward. If this pattern becomes more common, consider extracting it into a small helper extension function to improve readability:private fun MediaLibrarySession?.setPlayer(player: ExoPlayer) { this?.let { (it as MediaSession).player = player } }Then usage becomes:
mediaSession.setPlayer(newPlayer).Also applies to: 4406-4406
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` at line 910, The mediaSession?.let { (it as MediaSession).player = newPlayer } pattern is verbose and repeated; add a small nullable extension function like MediaLibrarySession?.setPlayer(player: ExoPlayer) that does the safe cast and assignment ((this as? MediaSession)?.player = player) and replace direct usages (e.g., mediaSession?.let { (it as MediaSession).player = newPlayer }) with mediaSession.setPlayer(newPlayer) to improve readability and avoid repeated casts; update all occurrences (including the one around symbol mediaSession and any similar uses at the other noted location) to call the new setPlayer extension.
374-374: 💤 Low valueConsider whether the
isRunningflag is necessary.The new
isRunningflag is set inonCreateandonDestroy, but it's not visibly used within the provided code changes. SincemediaSessionnullability now serves as a signal for whether the service initialized successfully, this additional flag may be redundant. If it's intended for external access or future defensive checks, consider documenting its purpose. Otherwise, it could be removed to reduce state tracking.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt` at line 374, The isRunning boolean field appears redundant because mediaSession nullability already indicates initialization; remove the private var isRunning = false declaration and any assignments to it in onCreate and onDestroy (or, if external visibility is required, replace it with a documented accessor that derives state from mediaSession != null). Locate usages of isRunning in MusicService, onCreate, and onDestroy and delete or refactor them to use mediaSession != null, and add a brief KDoc to the service if you keep a derived isRunning accessor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt`:
- Line 910: The mediaSession?.let { (it as MediaSession).player = newPlayer }
pattern is verbose and repeated; add a small nullable extension function like
MediaLibrarySession?.setPlayer(player: ExoPlayer) that does the safe cast and
assignment ((this as? MediaSession)?.player = player) and replace direct usages
(e.g., mediaSession?.let { (it as MediaSession).player = newPlayer }) with
mediaSession.setPlayer(newPlayer) to improve readability and avoid repeated
casts; update all occurrences (including the one around symbol mediaSession and
any similar uses at the other noted location) to call the new setPlayer
extension.
- Line 374: The isRunning boolean field appears redundant because mediaSession
nullability already indicates initialization; remove the private var isRunning =
false declaration and any assignments to it in onCreate and onDestroy (or, if
external visibility is required, replace it with a documented accessor that
derives state from mediaSession != null). Locate usages of isRunning in
MusicService, onCreate, and onDestroy and delete or refactor them to use
mediaSession != null, and add a brief KDoc to the service if you keep a derived
isRunning accessor.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2eeb0994-2bf8-42e3-b47a-66df195b81d0
📒 Files selected for processing (1)
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
|
I believe it is ready to review cc: @Dr-Brixx @nyxiereal |
Problem
Users were experiencing app crashes and playback failures due to an
UninitializedPropertyAccessExceptioninMusicService.onGetSession.Cause
MusicService.onCreate()could legitimately abort early due toensureStartedAsForegroundOrStop(). When this happens,mediaSession(alateinit var) was never initialized. However, the service could still be bound by Media3, causingonGetSessionto be called and throwing the crash when trying to access the uninitialized property.Solution
mediaSessionfromlateinit varto a properly modelledMediaLibrarySession? = null.?.) across all usages ofmediaSession.onGetSessionnow safely returnsnullwhen the service is stopped prematurely, correctly signaling Media3 to reject the controller connection without crashing.Testing
./gradlew :app:assembleFossDebug).Related Issues
Summary by CodeRabbit