In my last article “Implementing Video Playback on Android Jetpack Compose” I explained how to play videos with ExoPlayer in Jetpack Compose on Android.
A reader observed the following behaviour: when putting the example app into the background it kept playing. He asked how to make ExoPlayer lifecycle-aware so that the video stops when the app is 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 lifecycle events. Here is the full solution below. 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.
First we get the current instance of the LifecycleOwner:
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)Inside the scope of the DisposableEffect we 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 (goes into the background), the player also pauses. When the app resumes (returns to the foreground), the player continues playing.
Then we add this observer to the lifecycle instance:
val lifecycle = lifecycleOwner.value.lifecycle
lifecycle.addObserver(observer)We also need one more line for proper cleanup: when the app is closed, the observer must be removed from the lifecycle:
lifecycle.removeObserver(observer)That’s about it! Hope this helps with your project.
Thank you for reading!