Adicionar controles de mídia ao app

Um app que reproduz mídia precisa de componentes da interface do usuário para mostrar mídia e controlar a reprodução. A biblioteca Media3 inclui um módulo de interface que contém vários componentes de interface. Para depender do módulo da interface, adicione a seguinte dependência:

Kotlin

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

Groovy

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

O componente mais importante é PlayerView, uma visualização para reprodução de mídia. PlayerView exibe vídeo, imagens, legendas e capa do álbum durante a reprodução, bem como os controles de reprodução.

O PlayerView tem um método setPlayer para anexar e desconectar (transmitindo null) instâncias de jogadores.

PlayerView

O PlayerView pode ser usado para reprodução de vídeo, imagem e áudio. Ele renderiza vídeos e legendas no caso de reprodução de vídeo, bitmaps para reprodução de imagem e pode mostrar artes incluídas como metadados em arquivos de áudio. É possível incluí-lo nos arquivos de layout como qualquer outro componente de interface. Por exemplo, um PlayerView pode ser incluído com o seguinte 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"/>

O snippet acima ilustra que PlayerView fornece vários atributos. Esses atributos podem ser usados para personalizar o comportamento da visualização, bem como a aparência dela. A maioria desses atributos tem métodos setters correspondentes, que podem ser usados para personalizar a visualização no momento da execução. O Javadoc PlayerView lista esses atributos e métodos de setter com mais detalhes.

Depois que a visualização é declarada no arquivo de layout, ela pode ser pesquisada no método onCreate da atividade:

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);
}

Quando um player é inicializado, ele pode ser anexado à visualização chamando 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();

Escolher um tipo de plataforma

O atributo surface_type de PlayerView permite definir o tipo de superfície usado para a reprodução de vídeo. Além dos valores spherical_gl_surface_view (que é um valor especial para a reprodução de vídeo esférica) e video_decoder_gl_surface_view (que é para renderização de vídeo usando renderizadores de extensão), os valores permitidos são surface_view, texture_view e none. Se a visualização for apenas para reprodução de áudio, use none para evitar a necessidade de criar uma superfície, porque isso pode ser caro.

Se a visualização for para a reprodução de vídeos normais, use surface_view ou texture_view. O SurfaceView tem vários benefícios em relação ao TextureView para reprodução de vídeo:

  • Consumo de energia menor em muitos dispositivos.
  • Tempo de renderização de frames mais preciso, resultando em uma reprodução de vídeo mais suave.
  • Suporte para saída de vídeo HDR de maior qualidade em dispositivos compatíveis.
  • Suporte para saída segura ao reproduzir conteúdo protegido por DRM.
  • A capacidade de renderizar conteúdo de vídeo na resolução total da tela em dispositivos Android TV que aumentam a camada da interface.

Portanto, SurfaceView deve ser preferido em vez de TextureView, sempre que possível. O TextureView só deve ser usado se o SurfaceView não atender às suas necessidades. Um exemplo é quando animações ou rolagem suaves da superfície de vídeo são necessárias antes do Android 7.0 (nível 24 da API), conforme descrito nas notas a seguir. Nesse caso, é preferível usar TextureView apenas quando SDK_INT for menor que 24 (Android 7.0) e SurfaceView, caso contrário.

Navegação com D-pad no Android TV

O controle remoto do Android TV tem um botão direcional que envia comandos que chegam como um evento de tecla em dispatchKeyEvent(KeyEvent) das Activity. Eles precisam ser delegados à visualização do jogador:

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 o foco para a visualização do player é importante para navegar pelos controles de reprodução e pular anúncios. Considere solicitar o foco em onCreate do 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();
    // ...
}

Se você estiver usando o Compose no Android TV, será necessário tornar o AndroidView foco e delegar o evento transmitindo o parâmetro do modificador para o AndroidView de acordo:

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

Substituir drawables

O PlayerView usa PlayerControlView para mostrar os controles de reprodução e a barra de progresso. Os drawables usados por PlayerControlView podem ser substituídos por drawables com os mesmos nomes definidos no aplicativo. Consulte o Javadoc PlayerControlView para conferir uma lista de drawables de controle que podem ser substituídos.

Outras personalizações

Quando a personalização além da descrita acima for necessária, esperamos que os desenvolvedores de apps implementem os próprios componentes de interface em vez de usar os fornecidos pelo módulo de interface do Media3.