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.