Reproducción de audio y vídeo
Reproducción multimedia sencilla en Android
Reproducción de audio y vídeo es una lección gratuita de Android Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Android Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Android Academy incluye 4 lecciones en total.
Más allá de las imágenes: reproducción multimedia
Coil muestra imágenes de forma excelente, pero las aplicaciones también reproducen sonido y vídeo: un tono de notificación, un pódcast, un clip en segundo plano o un feed de vídeo. Android cuenta con API específicas para contenido multimedia.
La biblioteca moderna recomendada es Media3 (ExoPlayer). Gestiona la transmisión, los formatos, el almacenamiento en búfer y los controles de reproducción mucho mejor que el antiguo MediaPlayer. En esta lección reproducirá audio y vídeo sencillos en una aplicación de Compose.
Añadir dependencias de Media3
Media3 está dividida en módulos. Para la mayoría de las aplicaciones necesitará media3-exoplayer (el motor del reproductor) y media3-ui (vistas de reproductor listas para usar). Para vídeo en Compose también puede usar PlayerView mediante AndroidView.
// build.gradle.kts (module level)
dependencies {
implementation("androidx.media3:media3-exoplayer:1.5.0")
implementation("androidx.media3:media3-ui:1.5.0")
}Crear un ExoPlayer
Un ExoPlayer se crea a partir de un Context. Se le proporciona un MediaItem (una URL o un archivo local), se llama a prepare() y se inicia la reproducción. Se ejecuta en sus propios hilos, por lo que no bloquea la interfaz.
Es importante tener en cuenta que un reproductor mantiene recursos del sistema y debe liberarse; hablaremos de ello enseguida.
import android.content.Context
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
fun createPlayer(context: Context, url: String): ExoPlayer {
val player = ExoPlayer.Builder(context).build()
player.setMediaItem(MediaItem.fromUri(url))
player.prepare()
player.playWhenReady = true
return player
}Reproducir audio
Para reproducir solo audio, la configuración es idéntica; basta con apuntar MediaItem a una URL de audio (mp3, aac, etc.). No hay ninguna vista que mostrar, por lo que se controla mediante el objeto reproductor: play(), pause(), seekTo().
Esto es suficiente para crear un reproductor de pódcast o música.
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
fun playPodcast(player: ExoPlayer, audioUrl: String) {
player.setMediaItem(MediaItem.fromUri(audioUrl))
player.prepare()
player.play()
}
fun togglePause(player: ExoPlayer) {
if (player.isPlaying) player.pause() else player.play()
}Recordar el reproductor en Compose
En Compose debe crear el reproductor una sola vez y conservarlo entre recomposiciones. Use remember para evitar crear un reproductor nuevo en cada recomposición.
Combine esto con una limpieza adecuada (en la siguiente escena) para no provocar fugas de recursos.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
@Composable
fun rememberPlayer(url: String): ExoPlayer {
val context = LocalContext.current
return remember {
ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri(url))
prepare()
}
}
}Liberar el reproductor
Un reproductor mantiene activos los códecs, los búferes y el foco de audio. Si olvida liberarlo, provoca una fuga de memoria y puede hacer que la reproducción continúe después de que desaparezca la pantalla. En Compose, DisposableEffect ejecuta la limpieza cuando el composable sale de la composición.
Llame siempre a player.release() allí.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.media3.exoplayer.ExoPlayer
@Composable
fun ManagedPlayer(player: ExoPlayer) {
DisposableEffect(player) {
onDispose {
player.release()
}
}
// ... use player here
}Mostrar vídeo con PlayerView
Media3 proporciona un PlayerView listo para usar con controles. Compose no tiene un composable de vídeo nativo, por lo que debe insertar la vista mediante AndroidView y asociarle el reproductor.
Así obtiene controles de reproducción y pausa, una barra de búsqueda y pantalla completa sin trabajo adicional.
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
@Composable
fun VideoPlayer(player: ExoPlayer, modifier: Modifier = Modifier) {
AndroidView(
factory = { context ->
PlayerView(context).apply {
this.player = player
}
},
modifier = modifier
)
}Una pantalla de vídeo completa
Vamos a unirlo todo: cree el reproductor, recuérdelo, asígnelo a un PlayerView y libérelo al eliminarlo. Esta es una pantalla de vídeo independiente que puede reutilizar.
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
@Composable
fun VideoScreen(videoUrl: String) {
val context = LocalContext.current
val player = remember {
ExoPlayer.Builder(context).build().apply {
setMediaItem(MediaItem.fromUri(videoUrl))
prepare()
playWhenReady = true
}
}
DisposableEffect(Unit) { onDispose { player.release() } }
AndroidView(
factory = { PlayerView(it).apply { this.player = player } },
modifier = Modifier.fillMaxWidth().height(220.dp)
)
}Seguir el estado de reproducción
Para actualizar la interfaz (un icono de reproducción/pausa o una barra de progreso), escuche al reproductor con un Player.Listener. Este informa de cambios de estado, como almacenamiento en búfer, listo y finalizado, además de indicar si la reproducción está activa.
Añada el listener cuando aparezca la pantalla y elimínelo al eliminarla.
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
fun observe(player: ExoPlayer, onPlaying: (Boolean) -> Unit): Player.Listener {
val listener = object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
onPlaying(isPlaying)
}
override fun onPlaybackStateChanged(state: Int) {
when (state) {
Player.STATE_BUFFERING -> { /* show spinner */ }
Player.STATE_READY -> { /* ready */ }
Player.STATE_ENDED -> { /* finished */ }
}
}
}
player.addListener(listener)
return listener
}Pausar cuando la aplicación pasa a segundo plano
Para vídeo integrado (no una aplicación de música), normalmente querrá pausarlo cuando el usuario abandone la pantalla y reanudarlo cuando vuelva. Puede vincular la reproducción al ciclo de vida de Compose observando Lifecycle y pausando en ON_PAUSE.
Así evita reproducir un vídeo que el usuario no puede ver y ahorra batería.
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.media3.exoplayer.ExoPlayer
@Composable
fun PauseWithLifecycle(player: ExoPlayer) {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> player.pause()
Lifecycle.Event.ON_RESUME -> player.play()
else -> {}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}
}Audio en segundo plano con MediaSession
Para el audio que debe seguir reproduciéndose cuando la aplicación pasa a segundo plano (música o pódcasts), incluya la reproducción en un MediaSessionService. Esto se integra con los controles del sistema, la pantalla de bloqueo y los botones Bluetooth.
Es algo más complejo, pero la idea principal es exponer el reproductor mediante una MediaSession.
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
class PlaybackService : MediaSessionService() {
private var session: MediaSession? = null
override fun onCreate() {
super.onCreate()
val player = ExoPlayer.Builder(this).build()
session = MediaSession.Builder(this, player).build()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo) = session
override fun onDestroy() {
session?.run { player.release(); release() }
session = null
super.onDestroy()
}
}Comprobación rápida
En una pantalla de Compose que contiene un ExoPlayer, ¿qué API de Compose debe usar para liberar el reproductor cuando la pantalla sale de la composición?
Resumen
Ha añadido reproducción de audio y vídeo:
- Use Media3 ExoPlayer, el sustituto moderno de MediaPlayer.
- Cree un reproductor, establezca un
MediaItem, llame aprepare()y después aplay(). - En Compose, recuerde el reproductor con
remembery libérelo enDisposableEffect, dentro deonDispose. - Muestre vídeo insertando
PlayerViewconAndroidView. - Siga el estado con un
Player.Listener; use unMediaSessionServicepara el audio en segundo plano.
Con esto completa el curso Carga de imágenes y contenido multimedia con Coil. Ahora puede cargar imágenes fluidamente y reproducir contenido multimedia de la forma moderna en Android.
Preguntas frecuentes
¿La lección «Reproducción de audio y vídeo» es gratis?
Sí — el texto completo de «Reproducción de audio y vídeo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Android Academy, actualiza a CoddyKit PRO. El curso de Android Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Reproducción de audio y vídeo»?
Reproducción multimedia sencilla en Android Practicas Android Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Android Academy?
No se requiere experiencia previa. Android Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Reproducción de audio y vídeo»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Android Academy?
Sí. Cada lección de Android Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Carga de imágenes con Coil
- Marcadores de posición y estados de error
- Caché y rendimiento
- Reproducción de audio y vídeo