Cómo agregar controles de reproducción a tu app

Una app que reproduce contenido multimedia requiere componentes de la interfaz de usuario para mostrar contenido multimedia y controlar la reproducción. La biblioteca Media3 incluye un módulo de IU que contiene varios componentes de la IU. Para depender del módulo de la IU, agrega la siguiente dependencia:

Kotlin

implementation("androidx.media3:media3-ui:1.3.1")

Groovy

implementation "androidx.media3:media3-ui:1.3.1"

El componente más importante es PlayerView, una vista para reproducciones de contenido multimedia. PlayerView muestra el video, los subtítulos, las imágenes del álbum y los controles de reproducción durante la reproducción.

PlayerView tiene un método setPlayer para conectar y desconectar (pasando null) instancias del jugador.

Vista del reproductor

PlayerView se puede utilizar para reproducciones de video y audio. Renderiza videos y subtítulos en el caso de la reproducción de video, y puede mostrar material gráfico incluido como metadatos en archivos de audio. Puedes incluirlo en tus archivos de diseño como cualquier otro componente de la IU. Por ejemplo, se puede incluir un PlayerView con el siguiente XML:

<androidx.media3.ui.PlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:show_buffering="when_playing"
    app:show_shuffle_button="true"/>

En el fragmento anterior, se ilustra que PlayerView proporciona varios atributos. Estos atributos se pueden usar para personalizar el comportamiento de la vista, así como su apariencia. La mayoría de estos atributos tienen métodos set correspondientes, que se pueden usar para personalizar la vista en el tiempo de ejecución. El Javadoc de PlayerView enumera estos atributos y métodos set con más detalle.

Una vez que se declara la vista en el archivo de diseño, se puede buscar en el método onCreate de la actividad:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  // ...
  playerView = findViewById(R.id.player_view)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // ...
  playerView = findViewById(R.id.player_view);
}

Una vez que se inicializa un reproductor, se puede adjuntar a la vista llamando a setPlayer:

Kotlin

// Instantiate the player.
val player = ExoPlayer.Builder(context).build()
// Attach player to the view.
playerView.player = player
// Set the media item to be played.
player.setMediaItem(mediaItem)
// Prepare the player.
player.prepare()

Java

// Instantiate the player.
player = new ExoPlayer.Builder(context).build();
// Attach player to the view.
playerView.setPlayer(player);
// Set the media item to be played.
player.setMediaItem(mediaItem);
// Prepare the player.
player.prepare();

Elige un tipo de superficie

El atributo surface_type de PlayerView te permite establecer el tipo de superficie que se usa para la reproducción de video. Además de los valores spherical_gl_surface_view (que es un valor especial para la reproducción de video esférica) y video_decoder_gl_surface_view (que es para la renderización de videos con procesadores de extensión), los valores permitidos son surface_view, texture_view y none. Si la vista es solo para reproducción de audio, se debe usar none para evitar tener que crear una plataforma, ya que hacerlo puede ser costoso.

Si la vista es para la reproducción de video normal, se deben usar surface_view o texture_view. SurfaceView tiene una serie de beneficios en comparación con TextureView para la reproducción de video:

  • Un consumo de energía mucho más bajo en muchos dispositivos.
  • Latencia de fotogramas más precisa, lo que brinda una reproducción de video más fluida
  • Compatibilidad con salidas de video HDR de mayor calidad en dispositivos compatibles.
  • Compatibilidad con un formato de salida seguro cuando se reproduce contenido protegido por DRM.
  • La capacidad de renderizar contenido de video en la resolución completa de la pantalla en dispositivos Android TV que optimizan la capa de la IU

Por lo tanto, se debe preferir SurfaceView en lugar de TextureView siempre que sea posible. Solo debes usar TextureView si SurfaceView no satisface tus necesidades. Un ejemplo es cuando se requieren animaciones fluidas o desplazamiento por la superficie de video en versiones anteriores a Android 7.0 (nivel de API 24), como se describe en las siguientes notas. En este caso, es preferible usar TextureView solo cuando SDK_INT es inferior a 24 (Android 7.0) y SurfaceView en el caso contrario.

Navegación con pad direccional en Android TV

El control remoto de Android TV tiene un control de pad direccional que envía comandos que llegan como evento de tecla a dispatchKeyEvent(KeyEvent) de tu Activity. Estos se deben delegar a la vista del jugador:

Kotlin

override fun dispatchKeyEvent(event: KeyEvent?): Boolean{
  return playerView.dispatchKeyEvent(event!!) || super.dispatchKeyEvent(event)
}

Java

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
  return playerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
}

Solicitar el enfoque para la vista del reproductor es importante para navegar por los controles de reproducción y omitir anuncios. Considera solicitar el enfoque en onCreate de Activity:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  // ...
  playerView.requestFocus()
  // ...
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    playerView.requestFocus();
    // ...
}

Si usas Compose en Android TV, debes hacer que AndroidView se pueda enfocar y delegar el evento. Para ello, pasa el parámetro modificador a AndroidView según corresponda:

AndroidView(
  modifier = modifier
    .focusable()
    .onKeyEvent { playerView.dispatchKeyEvent(it.nativeKeyEvent) },
  factory = { playerView }
)

Cómo anular elementos de diseño

PlayerView usa PlayerControlView para mostrar los controles de reproducción y la barra de progreso. Los elementos de diseño con los mismos nombres definidos en tu aplicación pueden anular los elementos de diseño que usa PlayerControlView. Consulta el Javadoc de PlayerControlView para obtener una lista de los elementos de diseño de control que se pueden anular.

Mayor personalización

Cuando se requiera una personalización más allá de la descrita anteriormente, esperamos que los desarrolladores de apps implementen sus propios componentes de IU en lugar de usar los proporcionados por el módulo de la IU de Media3.