From c74a8f9f0752287c1ac28c7700ca9baa916fdbf7 Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Tue, 28 Jun 2022 10:43:56 +0200 Subject: [PATCH] Dispose PlayerState --- .../vimusic/services/PlayerService.kt | 4 +- .../vfsfitvnm/vimusic/ui/views/PlayerView.kt | 2 +- .../it/vfsfitvnm/vimusic/utils/PlayerState.kt | 53 ++++++++++------ .../vfsfitvnm/vimusic/utils/YoutubePlayer.kt | 62 +++++++------------ 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt index 8bd65bb..e127cdf 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt @@ -77,7 +77,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback private var lastArtworkUri: Uri? = null private var lastBitmap: Bitmap? = null - private var radio: YoutubePlayer.Radio? = null + private var radio: YouTubeRadio? = null private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job() @@ -549,7 +549,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback private fun startRadio(endpoint: NavigationEndpoint.Endpoint.Watch?, justAdd: Boolean) { radioJob?.cancel() radio = null - YoutubePlayer.Radio( + YouTubeRadio( endpoint?.videoId, endpoint?.playlistId, endpoint?.playlistSetVideoId, diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt index 8b3b077..fad94ca 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt @@ -73,7 +73,7 @@ fun PlayerView( val context = LocalContext.current val player = binder?.player - val playerState = rememberYoutubePlayer(player) + val playerState = rememberPlayerState(player) val coroutineScope = rememberCoroutineScope() diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt index 02cc569..9c85689 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/PlayerState.kt @@ -7,7 +7,7 @@ import androidx.media3.common.* import kotlin.math.absoluteValue @Stable -open class PlayerState(private val player: Player) : Player.Listener { +class PlayerState(private val player: Player) : Player.Listener, Runnable { private val handler = Handler(Looper.getMainLooper()) var currentPosition by mutableStateOf(player.currentPosition) @@ -30,9 +30,6 @@ open class PlayerState(private val player: Player) : Player.Listener { var mediaMetadata by mutableStateOf(player.mediaMetadata) private set - var isPlaying by mutableStateOf(player.isPlaying) - private set - var playWhenReady by mutableStateOf(player.playWhenReady) private set @@ -47,16 +44,6 @@ open class PlayerState(private val player: Player) : Player.Listener { var volume by mutableStateOf(player.volume) private set - init { - handler.post(object : Runnable { - override fun run() { - duration = player.duration - currentPosition = player.currentPosition - handler.postDelayed(this, 500) - } - }) - } - override fun onVolumeChanged(volume: Float) { this.volume = volume } @@ -69,10 +56,6 @@ open class PlayerState(private val player: Player) : Player.Listener { this.mediaMetadata = mediaMetadata } - override fun onIsPlayingChanged(isPlaying: Boolean) { - this.isPlaying = isPlaying - } - override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) { this.playWhenReady = playWhenReady } @@ -94,4 +77,38 @@ open class PlayerState(private val player: Player) : Player.Listener { mediaItems = timeline.mediaItems mediaItemIndex = player.currentMediaItemIndex } + + override fun run() { + duration = player.duration + currentPosition = player.currentPosition + handler.postDelayed(this, 500) + } + + fun init() { + player.addListener(this) + handler.post(this) + } + + fun dispose() { + player.removeListener(this) + handler.removeCallbacks(this) + } +} + +@Composable +fun rememberPlayerState( + player: Player? +): PlayerState? { + val playerState = remember(player) { + player?.let(::PlayerState) + } + + playerState?.let { + DisposableEffect(Unit) { + playerState.init() + onDispose(playerState::dispose) + } + } + + return playerState } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt index 1890f30..c4eabe2 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/YoutubePlayer.kt @@ -2,54 +2,40 @@ package it.vfsfitvnm.vimusic.utils import androidx.compose.runtime.* import androidx.media3.common.MediaItem -import androidx.media3.common.Player import it.vfsfitvnm.youtubemusic.Outcome import it.vfsfitvnm.youtubemusic.YouTube import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -class YoutubePlayer(player: Player) : PlayerState(player) { - data class Radio( - private val videoId: String? = null, - private val playlistId: String? = null, - private val playlistSetVideoId: String? = null, - private val parameters: String? = null - ) { - var nextContinuation by mutableStateOf>(Outcome.Initial) +data class YouTubeRadio( + private val videoId: String? = null, + private val playlistId: String? = null, + private val playlistSetVideoId: String? = null, + private val parameters: String? = null +) { + var nextContinuation by mutableStateOf>(Outcome.Initial) - suspend fun process(): List { - val token = nextContinuation.valueOrNull + suspend fun process(): List { + val token = nextContinuation.valueOrNull - nextContinuation = Outcome.Loading + nextContinuation = Outcome.Loading - var mediaItems: List? = null + var mediaItems: List? = null - nextContinuation = withContext(Dispatchers.IO) { - YouTube.next( - videoId = videoId ?: error("This should not happen"), - playlistId = playlistId, - params = parameters, - playlistSetVideoId = playlistSetVideoId, - continuation = token - ) - }.map { nextResult -> - mediaItems = nextResult.items?.map(YouTube.Item.Song::asMediaItem) + nextContinuation = withContext(Dispatchers.IO) { + YouTube.next( + videoId = videoId ?: error("This should not happen"), + playlistId = playlistId, + params = parameters, + playlistSetVideoId = playlistSetVideoId, + continuation = token + ) + }.map { nextResult -> + mediaItems = nextResult.items?.map(YouTube.Item.Song::asMediaItem) - nextResult.continuation?.takeUnless { token == nextResult.continuation } - }.recoverWith(token) + nextResult.continuation?.takeUnless { token == nextResult.continuation } + }.recoverWith(token) - return mediaItems ?: emptyList() - } - } -} - -@Composable -fun rememberYoutubePlayer( - player: Player? -): YoutubePlayer? { - return remember(player) { - YoutubePlayer(player ?: return@remember null).also { - player.addListener(it) - } + return mediaItems ?: emptyList() } }