Blog Infos

Media3’s 1.6.0 version introduced a new module media3-ui-compose, which provides state classes linked to the player, that we can use to build compose-based user interfaces (UIs).
Here is a list of state classes available for developing custom UIs based on them. 👇

Current state of Android Development — Player integration
- To integrate player-related functionality in our compose-based applications, we need
AndroidView +PlayerView
@Composable
fun ExoPlayerComposable(
videoUri: String,
) {
val context = LocalContext.current
val lifecycleOwner by rememberUpdatedState(LocalLifecycleOwner.current)
val lifecycle = lifecycleOwner.lifecycle
val exoPlayer = remember {
ExoPlayer.Builder(context)
.build()
.also { exoPlayer ->
val mediaItem = MediaItem.Builder()
.setUri(videoUri)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.addListener()
}
}
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.pause()
}
Lifecycle.Event.ON_RESUME -> {
exoPlayer.play()
}
else -> {}
}
}
lifecycle.addObserver(observer)
onDispose {
exoPlayer.release()
lifecycle.removeObserver(observer)
}
}
AndroidView(
factory = {
PlayerView(context).apply {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
player = exoPlayer
}
},
modifier = Modifier
.fillMaxWidth()
.aspectRatio(aspectRatio)
)
}
Using new state classes — Implementation + Demo 🧑💻
- PlayerSurface — It is a Composable that represents a dedicated drawing surface for showing videos 🎥
Connects to Player, but does not contain playback controls.
- State classes — provide different states, such as play, pause, next, and previous ⏭, ⏮, ⏯
Implementation
@Composable
fun ExoPlayerComposableBasedOnNewModule(
lifecycle: Lifecycle,
lifecycleOwner: LifecycleOwner,
videoUri: String,
) {
val context = LocalContext.current
var showControls by remember { mutableStateOf(true) }
val exoPlayer = remember {
ExoPlayer.Builder(context)
.build()
.also { exoPlayer ->
val mediaItem = MediaItem.Builder()
.setUri(videoUri)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
}
}
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.pause()
}
Lifecycle.Event.ON_RESUME -> {
exoPlayer.play()
}
else -> {}
}
}
lifecycle.addObserver(observer)
onDispose {
exoPlayer.release()
lifecycle.removeObserver(observer)
}
}
Box(modifier = Modifier.fillMaxSize()) {
PlayerSurface(player = exoPlayer)
if (showControls) {
PlayPauseButton(exoPlayer)
}
}
}
⏯️ Play/Pause button UI based on The PlayPauseButtonState
@Composable
fun PlayPauseButton(player: Player, modifier: Modifier = Modifier) {
val state = rememberPlayPauseButtonState(player)
val icon = if (state.showPlay) Icons.Default.PlayArrow else Icons.Default.Pause
val contentDescription =
if (state.showPlay) stringResource(R.string.lbl_play_state) else stringResource(
R.string.lbl_pause_state
)
val graySemiTransparentBG = Color.Gray.copy(alpha = 0.1f)
val btnModifier =
modifier
.size(100.dp)
.background(graySemiTransparentBG, CircleShape)
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(
onClick = state::onClick,
modifier = btnModifier,
enabled = state.isEnabled
) {
Icon(icon, contentDescription = contentDescription)
}
}
}
PlayPauseButtonState — class gives us two properties, isEnabled and showPlay, that we can use in our code to update the content description and UI state of the Play/Pause button ⏯
Limitations
- This is just the beginning of first-class support for developing Media3-related features in Android applications based on compose UIs
- Currently, 🛑 Previews don’t work —
@Preview
@Composable
private fun PreviewMyVideoPlayer() {
val player = ExoPlayer.Builder(LocalContext.current).build().apply {
setMediaItem(MediaItem.fromUri("uri.mp4"))
playWhenReady = true
prepare()
}
PlayPauseButton(player = player)
}
Job Offers
- 🛑 Player instantiation fails during previews

- So I hope we get these sorts of issues fixed in the upcoming release of this module.
Demo 🎥

- In this article, we only covered the PlayPauseButtonState . Feel free to check the complete sample code for other states in this repository 👇
References
This article was previously published on proandroiddev.com.



