How to Make Exoplayer Lifecycle Aware in Jetpack Compose
In my last article “Implementing Video Playback on Android Jetpack Compose” I have explained how to play videos with ExoPlayer in Jetpack Compose on Android.
https://itnext.io/implementing-video-playback-on-android-jetpack-compose-f73b437560ea
A reader observed the following behaviour: When putting the example app into the background it was still playing. He asked the question how to make ExoPlayer lifecycle aware so that the video stops when the app is being suspended.
Let’s recap the code from the last article, which is a @Composable
that holds the ExoPlayer
inside an AndroidView
:
@Composable
fun VideoView(videoUri: String) {
val context = LocalContext.current
val exoPlayer = ExoPlayer.Builder(LocalContext.current)
.build()
.also { exoPlayer ->
val mediaItem = MediaItem.Builder()
.setUri(videoUri)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
}
DisposableEffect(
AndroidView(factory = {
StyledPlayerView(context).apply {
player = exoPlayer
}
})
) {
onDispose { exoPlayer.release() }
}
}
What we need is a current instance of the LocalLifeCycleOwner
that “tells” us about the lifecycle events that are happening. Here is the full solution right away. I will explain the details step-by-step after it.
@Composable
fun VideoView(videoUri: String) {
val context = LocalContext.current
val exoPlayer = ExoPlayer.Builder(LocalContext.current)
.build()
.also { exoPlayer ->
val mediaItem = MediaItem.Builder()
.setUri(videoUri)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
}
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
DisposableEffect(
AndroidView(factory = {
StyledPlayerView(context).apply {
player = exoPlayer
}
})
) {
val observer = LifecycleEventObserver { owner, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.pause()
}
Lifecycle.Event.ON_RESUME -> {
exoPlayer.play()
}
}
}
val lifecycle = lifecycleOwner.value.lifecycle
lifecycle.addObserver(observer)
onDispose {
exoPlayer.release()
lifecycle.removeObserver(observer)
}
}
}
Let me give you some explanation around it.
First we get the current instance of the LifecycleOwner
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
Inside the scope of the DisposableEffect
we first create a LifecycleEventObserver
.
val observer = LifecycleEventObserver { owner, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.pause()
}
Lifecycle.Event.ON_RESUME -> {
exoPlayer.play()
}
}
}
When the app pauses, when it goes into the background, the player also pauses. When the app is being resumed, coming back into the foreground, the player continues playing the video.
Then we add this observer to the lifecycle instance.
val lifecycle = lifecycleOwner.value.lifecycle
lifecycle.addObserver(observer)
We need to add one more line that is needed for a proper cleanup. When the app is being closed, the observer needs to be removed from the lifecycle
lifecycle.removeObserver(observer)
That’s about it! Hope this will help you with your project!
Thank you for reading!
- If you enjoyed this, please follow me on Medium
- Buy me a coffee to keep me going
- Support me and other Medium writers by signing up here
https://twissmueller.medium.com/membership