How to Make Exoplayer Lifecycle Aware in Jetpack Compose
In my last article “[[2022-08-18 Implementing Video Playback on Android Jetpack Compose | 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!