Adicionar controles de mídia ao app

Um app que reproduz mídia requer componentes de interface do usuário para exibir 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.3.1")

Groovy

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

O componente mais importante é a PlayerView, uma visualização para reproduções de mídia. PlayerView mostra o vídeo, as legendas e a capa do álbum durante a reprodução, além dos controles de reprodução.

PlayerView tem um método setPlayer para anexar e remover (transmitindo null) instâncias de jogador.

Visualização do player

PlayerView pode ser usado para reproduções de vídeo e áudio. Ela renderiza vídeo e legendas no caso de reprodução de vídeo, além de poder exibir artes incluídas como metadados em arquivos de áudio. Você pode incluí-lo nos arquivos de layout como qualquer outro componente de interface. Por exemplo, um PlayerView pode ser incluído com este 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 e a aparência da visualização. A maioria desses atributos tem métodos setter correspondentes, que podem ser usados para personalizar a visualização no momento da execução. O Javadoc PlayerView lista esses atributos e métodos setter em 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();

Escolha um tipo de superfície

O atributo surface_type do PlayerView permite definir o tipo de superfície usado para reprodução de vídeo. Além dos valores spherical_gl_surface_view (que é um valor especial para reprodução de vídeo esférico) 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, none precisará ser usado para evitar a necessidade de criar uma superfície, porque isso pode ser caro.

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

  • Um consumo de energia significativamente menor em muitos dispositivos.
  • Tempo para a renderização do frame mais precisa, resultando em uma reprodução de vídeo mais suave.
  • Compatível com saída de vídeo HDR de maior qualidade em dispositivos compatíveis.
  • Compatibilidade com saída segura ao reproduzir conteúdo protegido por DRM.
  • Capacidade de renderizar conteúdo de vídeo na resolução máxima da tela em dispositivos Android TV que melhoram a camada de interface.

SurfaceView precisa ter preferência sobre TextureView sempre que possível. Use TextureView apenas se SurfaceView não atender às suas necessidades. Um exemplo é quando as animações suaves ou a rolagem da superfície de vídeo são necessárias antes do Android 7.0 (nível 24 da API), conforme descrito nas observações abaixo. Para esse caso, é preferível usar TextureView somente quando SDK_INT for anterior a 24 (Android 7.0) e SurfaceView caso contrário.

Navegação com botão direcional no Android TV

O controle remoto do Android TV tem um botão direcional que envia comandos que chegam como evento de tecla às dispatchKeyEvent(KeyEvent) da Activity. Os aspectos 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 focável e delegar o evento transmitindo o parâmetro do modificador para AndroidView adequadamente:

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

Substituir drawables

PlayerView usa PlayerControlView para exibir 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 app. Consulte o Javadoc PlayerControlView (link em inglês) para uma lista de drawables de controle que podem ser substituídos.

Mais personalização

Quando uma 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.