Media streaming com ExoPlayer

4ec261ee5a0bd0cc.png

Screenshot: O aplicativo do YouTube Android

ExoPlayer é um reprodutor de mídia de nível de aplicativo construído sobre APIs de mídia de baixo nível no Android. O ExoPlayer tem uma série de vantagens sobre o MediaPlayer incorporado no Android. Ele suporta muitos dos mesmos formatos de mídia do MediaPlayer, além de formatos adaptativos, tais como DASH e SmoothStreaming. O ExoPlayer é altamente personalizável e extensível, tornando-o capaz de muitos casos de utilização avançada. É um projeto de código aberto usado pelas aplicações Google, incluindo YouTube e Google Play Movies & TV.

Prerequisites

  • Conhecimento moderado do desenvolvimento do Android e Android Studio

O que você fará

  • Criar uma instância SimpleExoPlayer, que prepara e reproduz mídia de uma variedade de fontes.
  • Integra o ExoPlayer com o ciclo de vida da atividade do aplicativo para suportar backgrounding, foregrounding e retomada da reprodução em um ambiente de uma ou várias janelas.
  • Utilizar MediaItems para criar uma lista de reprodução.
  • Tocar streams de vídeo adaptáveis, que adaptam a qualidade de mídia à largura de banda disponível.
  • Registar ouvintes de eventos para monitorar o estado de reprodução e mostrar como os ouvintes podem ser usados para medir a qualidade da reprodução.
  • Utilizar componentes ExoPlayer UI padrão, depois personalize-os ao estilo do seu aplicativo.

O que você vai precisar

  • Android Studio versão 3.5 ou superior
  • Um dispositivo Android com JellyBean (4.1) ou superior, idealmente com Nougat (7.1) ou superior, pois suporta múltiplas janelas.

Apanhe o código

Para começar, baixe o projeto Android Studio:

Download zip

Alternativamente, você pode clonar o repositório GitHub:

git clone https://github.com/googlecodelabs/exoplayer-intro.git

Estrutura diretiva

Clonar ou descompactar fornece uma pasta raiz (exoplayer-intro), que contém uma pasta para cada etapa deste codelab, juntamente com todos os recursos necessários:

/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-00/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-01/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-02/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-03/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-04

As pastas exoplayer-codelab-N (onde N é 00 a 04) contêm o estado final desejado de cada etapa deste codelab. Estes são projectos autónomos do Android Studio, que podem ser importados.

Importar o projecto inicial

  1. Iniciar Android Studio.
  2. Seleccionar ficheiro > Novo > Importar projecto*.*
  3. Importar o projecto inicial de exoplayer-codelab-00.

f2e5feb9ade6c7f7.png

Screenshot: Estrutura do projeto ao importar

Após os acabamentos da construção, você vê dois módulos: o módulo app (de tipo aplicação) e o módulo player-lib (de tipo biblioteca). O módulo app está na verdade vazio, tendo apenas um manifesto. Tudo do módulo player-lib é fundido quando a aplicação é construída usando uma dependência de gradle em app/build.gradle.

app/build.gradle

dependencies { implementation project(":player-lib")}

Seu media player Atividade é mantida no módulo player-lib. A razão para mantê-la em um módulo de biblioteca separado é para que você possa compartilhá-la entre APKs visando diferentes plataformas, como celular e Android TV. Ele também permite que você tire proveito de recursos, como o Dynamic Delivery, que permite que o recurso de reprodução de mídia seja instalado somente quando o usuário precisar.

  1. Desenvolver e executar o aplicativo para verificar se tudo está bem. O aplicativo deve preencher a tela com um fundo preto.

21c0dae6245fbd31.png

Screenshot: Aplicação em branco a correr

Adicionar dependência ExoPlayer

ExoPlayer é um projecto de código aberto alojado no GitHub. Cada versão é distribuída através do jCenter, que é um dos repositórios de pacotes padrão usados pelo Android Studio e Gradle. Cada versão é unicamente identificada por uma string com o seguinte formato:

com.google.android.exoplayer:exoplayer:rX.X.X

Você pode adicionar o ExoPlayer ao seu projeto simplesmente importando suas classes e componentes UI. É bastante pequeno, tendo uma pegada encolhida de cerca de 70 a 300 kB, dependendo das características incluídas e formatos suportados. A biblioteca do ExoPlayer é dividida em módulos para permitir que os desenvolvedores importem apenas as funcionalidades de que necessitam. Para mais informações sobre a estrutura modular do ExoPlayer, veja Add ExoPlayer modules.

  1. Abrir o arquivo build.gradle do arquivo player-lib module.
  2. Adicionar as seguintes linhas à seção dependencies e sincronizar o projeto.

player-lib/build.gradle

dependencies { implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.0'}

Adicionar o elemento PlayerView

  1. Abrir o arquivo de recurso de layout activity_player.xml do arquivo player-lib module.
  2. Pôr o cursor dentro do elemento FrameLayout> element.
  3. Iniciar a digitação <PlayerView e deixar o Android Studio autocompletar o elemento PlayerView.
  4. Utilizar match_parent para o width e height.
  5. Declarar a id como video_view.

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>

Vá em frente, você se refere a este elemento UI como a visualização do vídeo.

  1. No PlayerActivity, agora você precisa encontrar a visualização do vídeo para que você possa configurá-lo corretamente no método onCreate da atividade.

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
  1. Adicionar o campo de membro playerView à sua classe PlayerActivity. Certifique-se de que o tipo de vista é PlayerView.

Note: Use o recurso Quick Fix no Android Studio para adicionar um campo de membro automaticamente. Lembre-se de definir o tipo para

PlayerView

rather than the default

View

>b0f7f70115bb90e5.png

Screenshot: Quick fix menu for making a member field

Criar um ExoPlayer

Para reproduzir streaming media, você precisa de um objeto ExoPlayer. A maneira mais simples de criar um é usar a classe SimpleExoPlayer.Builder. Como o nome sugere, isto usa o padrão do construtor para construir uma SimpleExoPlayer instância.

SimpleExoPlayer é uma implementação conveniente e para todos os fins da ExoPlayer interface.

Adicionar um método privado initializePlayer para criar o seu objecto SimpleExoPlayer.

PlayerActivity.java

private SimpleExoPlayer player;private void initializePlayer() { player = new SimpleExoPlayer.Builder(this).build(); playerView.setPlayer(player);}

Criar um SimpleExoPlayer.Builder usando o seu contexto, depois ligue para build para criar o seu objecto SimpleExoPlayer. Isto é então atribuído a player, que você precisa declarar como um campo de membro. Você então usa playerView.setPlayer para ligar o player à sua visão correspondente.

Criar um item de mídia

Seu player agora precisa de algum conteúdo para reproduzir. Para isso, você cria um MediaItem. Existem muitos tipos diferentes de MediaItem, mas você começa criando um para um arquivo MP3 na internet.

A maneira mais simples de criar um MediaItem é usar MediaItem.fromUri, que aceita o URI de um arquivo de mídia. Adicione o MediaItem ao player usando player.setMediaItem.

  1. Adicione o seguinte código a initializePlayer:

PlayerActivity.java

private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.setMediaItem(mediaItem);}

Nota que R.string.media_url_mp3 é definida como https://storage.googleapis.com/exoplayer-test-media-0/play.mp3 em strings.xml.

Tocar bem com o ciclo de vida da atividade

Nossa player pode monopolizar muitos recursos, incluindo memória, CPU, conexões de rede e codecs de hardware. Muitos desses recursos estão em falta, particularmente para os codecs de hardware, onde pode haver apenas um. É importante que você libere esses recursos para que outros aplicativos sejam usados quando você não os estiver usando, como quando seu aplicativo for colocado em segundo plano.

Clique de outra forma, o ciclo de vida do seu player deve ser vinculado ao ciclo de vida do seu aplicativo. Para implementar isto, você precisa substituir os quatro métodos de PlayerActivity: onStart, onResume, onPause, e onStop.

  1. Com PlayerActivity abrir, clique no menu Código > Substituir métodos….
  2. Seleccionar onStart, onResume, onPause, e onStop.
  3. Initializar o jogador no nível onStart ou onResume Callback dependendo do nível da API.

PlayerActivity.java

@Overridepublic void onStart() { super.onStart(); if (Util.SDK_INT >= 24) { initializePlayer(); }}@Overridepublic void onResume() { super.onResume(); hideSystemUi(); if ((Util.SDK_INT < 24 || player == null)) { initializePlayer(); }}

Android API nível 24 e superior suporta múltiplas janelas. Como sua aplicação pode ser visível, mas não ativa no modo janela dividida, você precisa inicializar o jogador em onStart. Android API nível 24 e inferior requer que você espere o máximo de tempo possível até você pegar recursos, então você espera até onResume antes de inicializar o player.

  1. Adicionar o método hideSystemUi>

PlayerActivity.java

@SuppressLint("InlinedApi")private void hideSystemUi() { playerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}

hideSystemUi é um método de ajuda chamado em onResume, que permite que você tenha uma experiência em tela cheia.

  1. Largar recursos com releasePlayer (que você cria em breve) em onPause e onStop.

PlayerActivity.java

@Overridepublic void onPause() { super.onPause(); if (Util.SDK_INT < 24) { releasePlayer(); }}@Overridepublic void onStop() { super.onStop(); if (Util.SDK_INT >= 24) { releasePlayer(); }}

Com API nível 24 e inferior, não há garantia de onStop ser chamado, então você tem que liberar o jogador o mais cedo possível em onPause. Com a API Nível 24 e superior (que trouxe o modo multi- e split-window), onStop é garantido que será chamado. No estado pausado, sua atividade ainda é visível, então você espera para liberar o player até onStop.

Agora você precisa criar um método releasePlayer, que libera os recursos do player e o destrói.

  1. Adicionar o seguinte código à atividade:

PlayerActivity.java

private boolean playWhenReady = true;private int currentWindow = 0;private long playbackPosition = 0;private void releasePlayer() { if (player != null) { playWhenReady = player.getPlayWhenReady(); playbackPosition = player.getCurrentPosition(); currentWindow = player.getCurrentWindowIndex(); player.release(); player = null; }}

Antes de soltar e destruir o player, armazene as seguintes informações:

  • Tocar/pausar estado usando getPlayWhenReady.
  • Posição atual de reprodução usando getCurrentPosition.
  • Índice da janela atual usando getCurrentWindowIndex. Para mais informações sobre janelas, veja Linha do tempo.

Isso permite retomar a reprodução de onde o usuário parou. Tudo o que você precisa fazer é fornecer esta informação de estado quando você inicializa seu player.

Preparação final

Tudo o que você precisa fazer agora é fornecer a informação de estado que você salvou em releasePlayer ao seu player durante a inicialização.

  1. Adicionar o seguinte a initializePlayer:

PlayerActivity.java

private void initializePlayer() { player.setPlayWhenReady(playWhenReady); player.seekTo(currentWindow, playbackPosition); player.prepare();}

Aqui está o que está a acontecer:

  • setPlayWhenReady diz ao leitor se deve começar a reproduzir assim que todos os recursos para reprodução tenham sido adquiridos. Porque playWhenReady é inicialmente true, a reprodução começa automaticamente na primeira vez que o aplicativo é executado.
  • seekTo diz ao player para procurar uma determinada posição dentro de uma janela específica. Ambos currentWindow e playbackPosition são inicializados a zero para que a reprodução comece desde a primeira vez que o aplicativo for executado.
  • prepare diz ao player para adquirir todos os recursos necessários para a reprodução.

Play audio

Finalmente, você está pronto! Inicie o aplicativo para reproduzir o arquivo MP3 e veja a arte embutida.

1d049aead0483777.png

Screenshot: O aplicativo tocando uma única faixa.

Teste o ciclo de vida da atividade

Teste se o aplicativo funciona em todos os diferentes estados do ciclo de vida da atividade.

  1. Inicie outro aplicativo e coloque seu aplicativo em primeiro plano novamente. Ele retoma na posição correta?
  2. Pausa o aplicativo, e move-o para o segundo plano e depois para o primeiro plano novamente. Ele se mantém em pausa quando em segundo plano em estado de pausa?
  3. Rotate o aplicativo. Como ele se comporta se você mudar a orientação de retrato para paisagem e vice-versa?

Tocar vídeo

Se você quiser reproduzir vídeo, é tão fácil quanto modificar o item de mídia URI para um arquivo MP4.

  1. Mude o URI no ficheiro initializePlayer para R.string.media_url_mp4.
  2. Comece a aplicação novamente e teste o comportamento depois de ser reproduzido em segundo plano também.

PlayerActivity.java

private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); }

O ficheiro PlayerView faz tudo. Ao invés da arte, o vídeo é renderizado em tela cheia.

4ebd0b0f98593691.png

Screenshot: O aplicativo tocando vídeo.

Você é o máximo! Você acabou de criar um aplicativo para streaming de mídia em tela cheia no Android, completo com gerenciamento de ciclo de vida, estado salvo e controles UI!

Seu aplicativo atual reproduz um único arquivo de mídia, mas e se você quiser reproduzir mais de um arquivo de mídia, um após o outro? Para isso, você precisa de uma playlist.

Playlists podem ser criadas adicionando mais MediaItems ao seu player usando addMediaItem. Isto permite uma reprodução sem problemas e o buffer é manipulado em segundo plano para que o usuário não veja um spinner de buffer ao alterar itens de mídia.

  1. Adicionar o seguinte código para initializePlayer:

PlayerActivity.java

private void initializePlayer() { player.setMediaItem(mediaItem); // Existing code MediaItem secondMediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.addMediaItem(secondMediaItem); }

Verifica como os controles do player se comportam. Você pode usar 1f79fee4d082870f.png e 39627002c03ce320.png para navegar na seqüência de itens de mídia.

7b5c034dafabe1bd.png

Screenshot: Controles de reprodução mostrando um botão próximo e anterior

Isso é muito útil! Para mais informações, veja a documentação do desenvolvedor sobre Itens de Mídia e Listas de Reprodução, e este artigo sobre a API da Playlist.

Audaptive streaming é uma técnica para streaming de mídia variando a qualidade do stream com base na largura de banda disponível na rede. Isto permite ao usuário experimentar a melhor qualidade de mídia que sua largura de banda permite.

Tipicamente, o mesmo conteúdo de mídia é dividido em várias faixas com diferentes qualidades (bit rates e resoluções). O leitor escolhe uma faixa com base na largura de banda disponível na rede.

Cada faixa é dividida em pedaços de uma determinada duração, normalmente entre 2 e 10 segundos. Isto permite ao jogador alternar rapidamente entre as faixas conforme a largura de banda disponível. O leitor é responsável por juntar estes pedaços para uma reprodução sem falhas.

Selecção de faixa adaptável

No coração do streaming adaptável está a selecção da faixa mais apropriada para o ambiente actual. Atualize seu aplicativo para reproduzir streaming adaptativo usando a seleção de faixa adaptativa.

  1. Atualizar initializePlayer com o seguinte código:

PlayerActivity.java

private void initializePlayer() { if (player == null) { DefaultTrackSelector trackSelector = new DefaultTrackSelector(this); trackSelector.setParameters( trackSelector.buildUponParameters().setMaxVideoSizeSd()); player = new SimpleExoPlayer.Builder(this) .setTrackSelector(trackSelector) .build(); } // Remove or comment out. // player = new SimpleExoPlayer.Builder(this).build(); }

Primeiro, crie um DefaultTrackSelector, que é responsável por escolher as faixas no item de mídia. Depois, diga ao seu trackSelector para escolher apenas faixas de definição padrão ou inferior – uma boa maneira de salvar os dados do seu usuário às custas da qualidade. Finalmente, passe o seu trackSelector ao seu construtor para que ele seja utilizado na construção da SimpleExoPlayer instância.

Build um MediaItem adaptativo

DASH é um formato de streaming adaptativo amplamente utilizado. Para fazer streaming de conteúdo DASH, você precisa criar um MediaItem como antes. No entanto, desta vez, devemos usar um MediaItem.Builder em vez de fromUri.

Isto porque fromUri usa a extensão de arquivo para determinar o formato de mídia subjacente, mas o nosso DASH URI não tem uma extensão de arquivo, então devemos fornecer um tipo MIME de APPLICATION_MPD ao construir o MediaItem.

  1. Atualizar initializePlayer da seguinte forma:

PlayerActivity.java

  1. Reiniciar a aplicação e ver o streaming de vídeo adaptável com o DASH em acção. É muito fácil com ExoPlayer!

Outros formatos de streaming adaptativo

HLS (MimeTypes.APPLICATION_M3U8) e SmoothStreaming (MimeTypes.APPLICATION_SS) são outros formatos de streaming adaptativo comumente usados, ambos suportados pelo ExoPlayer. Para mais informações sobre a construção de outras fontes de mídia adaptativas, veja a demonstração do ExoPlayer app.

Nos passos anteriores, você aprendeu como fazer streaming de streams progressivos e adaptativos. O ExoPlayer está fazendo muito trabalho para você nos bastidores, incluindo o seguinte:

  • Alocar memória
  • Baixar arquivos do recipiente
  • Extrair metadados do recipiente
  • Decifrar dados
  • Renderizar vídeo, áudio e texto para a tela e alto-falantes

Por vezes, é útil saber o que o ExoPlayer está fazendo em tempo de execução para entender e melhorar a experiência de reprodução para seus usuários.

Por exemplo, você pode querer refletir as mudanças de estado de reprodução na interface do usuário fazendo o seguinte:

  • Exibir um spinner de carregamento quando o player entra em estado de buffering
  • Exibir uma overlay com opções de “watch next” quando a faixa tiver terminado

ExoPlayer oferece várias interfaces de ouvintes que fornecem callbacks para eventos úteis. Você usa um ouvinte para registrar em que estado o player está.

Ouvir

  1. Declare um membro privado do tipo PlaybackStateListener no PlayerActivity.
  2. Criar uma constante TAG, que você usa para registrar mais tarde.

PlayerActivity.java

private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
  1. Instanciar a playbackStateListener no início de onCreate (ainda não compilará, mas você corrigirá isso em breve).

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); playbackStateListener = new PlaybackStateListener();
  1. Utilizar Quick Fix para criar a classe interna PlaybackStateListener automaticamente.

b59ce69a22595ba7.png

Screenshot: Quick Fix menu para criar uma classe ausente

  1. Implementar a interface Player.EventListener. Isto é usado para informar sobre eventos importantes do player, incluindo erros e mudanças de estado de reprodução.
  2. Override onPlaybackStateChanged adicionando o seguinte código:

PlayerActivity.java

private class PlaybackStateListener implements Player.EventListener { @Override public void onPlaybackStateChanged(int playbackState) { String stateString; switch (playbackState) { case ExoPlayer.STATE_IDLE: stateString = "ExoPlayer.STATE_IDLE -"; break; case ExoPlayer.STATE_BUFFERING: stateString = "ExoPlayer.STATE_BUFFERING -"; break; case ExoPlayer.STATE_READY: stateString = "ExoPlayer.STATE_READY -"; break; case ExoPlayer.STATE_ENDED: stateString = "ExoPlayer.STATE_ENDED -"; break; default: stateString = "UNKNOWN_STATE -"; break; } Log.d(TAG, "changed state to " + stateString); }}

onPlaybackStateChanged é chamado quando o estado de reprodução muda. O novo estado é dado pelo parâmetro playbackState

O leitor pode estar num dos seguintes quatro estados:

State

Descrição

ExoPlayer.STATE_IDLE

>

O leitor foi instanciado, mas ainda não foi preparado.

ExoPlayer.STATE_BUFFERING

O jogador não é capaz de jogar a partir da posição atual porque não foram armazenados dados suficientes.

ExoPlayer.STATE_READY

O jogador é capaz de jogar imediatamente a partir da posição atual. Isto significa que o leitor começará a reproduzir media automaticamente se a propriedade do leitor WhenReady for true. Se for false, o player é pausado.

ExoPlayer.STATE_ENDED

O player terminou de tocar a mídia.

Registe o seu ouvinte

Para ter as suas chamadas de retorno, você precisa registrar o seu playbackStateListener com o player. Faça isso em initializePlayer.

  1. Registre o ouvinte antes que a reprodução seja preparada.

PlayerActivity.java

private void initializePlayer() { if (player == null) { player.addListener(playbackStateListener); player.prepare();}

Again, você precisa arrumar para evitar referências penduradas do player que poderiam causar um vazamento de memória.

  1. Remover o ouvinte em releasePlayer:

PlayerActivity.java

private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
  1. Abrir logcat e executar o app.
  2. Utilizar os controlos UI para procurar, pausar e retomar a reprodução. Você deve ver a mudança de estado da reprodução nos logs.

Vá mais fundo

ExoPlayer oferece vários outros ouvintes, que são úteis para entender a experiência de reprodução do usuário. Existem ouvintes para áudio e vídeo, assim como um AnalyticsListener, que contém as chamadas de retorno de todos os ouvintes. Alguns dos métodos mais importantes são os seguintes:

  • onRenderedFirstFrame é chamado quando o primeiro frame de um vídeo é renderizado. Com isto, você pode calcular quanto tempo o usuário teve que esperar para ver o conteúdo significativo na tela.
  • onDroppedVideoFrames é chamado quando os frames do vídeo são descartados. Frames perdidos indicam que a reprodução é janky e a experiência do usuário provavelmente será pobre.
  • onAudioUnderrun é chamada quando houve uma subexecução de áudio. Underruns causam falhas audíveis no som e são mais perceptíveis que quedas de quadros de vídeo.

AnalyticsListener podem ser adicionados a player com addAnalyticsListener. Há métodos correspondentes para os ouvintes de áudio e vídeo também.

Pense sobre quais eventos são importantes para o seu aplicativo e seus usuários. Para mais informações, consulte Ouvindo para eventos de player. É isso para ouvintes de eventos!

Até agora, você tem usado o ExoPlayer’s PlayerControlView para exibir um controlador de reprodução para o usuário.

bcfe17eebcad9e13.png

Screenshot: Controlador de reprodução padrão

E se você quiser alterar a funcionalidade ou o visual e a sensação desses controles? Felizmente, estes controles são altamente personalizáveis.

A primeira personalização simples é não usar o controlador de forma alguma. Isto pode ser feito facilmente usando o atributo use_controller no elemento PlayerView dentro de activity_player.xml.

  1. Set use_controller a false e o controle não aparece mais:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView app:use_controller="false"/>
  1. Adicionar o seguinte espaço de nomes ao seu FrameLayout:

activity_player.xml

<FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto">

Tente agora.

Personalize o comportamento

PlayerControlView tem vários atributos que afectam o seu comportamento. Use show_timeout, fastforward_increment, e rewind_increment para personalizar o comportamento do controlador.

  1. Remover app:use_controller="false".
  2. Mudar a vista do jogador para usar show_timeout, fastforward_increment e rewind_increment:

>

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:show_timeout="10000" app:fastforward_increment="30000" app:rewind_increment="30000"/>
  • O valor show_timeout diz ao PlayerView o atraso em milissegundos antes do controle ser escondido após a última interação do usuário com ele.
  • Os valores fastforward_increment e rewind_increment dizem ao jogador o tempo em milissegundos para saltar para a frente ou para trás quando o utilizador pressiona os botões de avanço rápido ou retrocesso.

Os atributos do PlayerControlView também podem ser programados.

Personalizar a aparência

Bem, isso é um bom começo. Mas e se você quiser que o PlayerControlView tenha uma aparência diferente ou mudar quais botões são exibidos? A implementação de PlayerControlView não assume que existam botões, por isso é fácil removê-los e adicionar novos.

Consulte como você pode personalizar o PlayerControlView.

  1. Criar um novo arquivo de layout custom_player_control_view.xml na pasta player-lib/res/layout/.
  2. No menu de contexto da pasta de layout, escolha New – Layout resource file e nomee-o custom_player_control_view.xml.

ae1e3795726d4e4e.png

Screenshot: O ficheiro de layout para a vista de controlo do leitor foi criado.

  1. Copiar o ficheiro de layout original daqui para custom_player_control_view.xml.
  2. Remover os elementos ImageButton com o id @id/exo_prev e @id/exo_next.

Para usar o seu layout personalizado, precisa de definir o atributo app:controller_layout_id do elemento PlayerView no ficheiro activity_player.xml

  1. Utilize o ID do layout do seu ficheiro personalizado como no seguinte código snippet:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:controller_layout_id="@layout/custom_player_control_view"/>

  1. Inicie a aplicação novamente. A vista de controlo do jogador já não tem os botões anterior e seguinte.

89e6535a22c8e321.png

Screenshot: Vista de controlo personalizada do leitor sem os botões anterior e seguinte

Pode aplicar as alterações que quiser no ficheiro de layout. Por padrão, as cores do tema do Android são escolhidas. Você pode substituir isto para combinar com o design do seu app.

  1. Adicionar um atributo android:tint a cada ImageButton element:

custom_player_control_view.xml

<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
  1. Mude todos android:textColor Atributos que você encontra no seu arquivo personalizado para a mesma cor: #FF00A6FF.

custom_player_control_view.xml

<TextView android:id="@id/exo_position" android:textColor="#FF00A6FF"/><TextView android:id="@id/exo_duration" android:textColor="#FF00A6FF"/>
  1. Executar o aplicativo. Agora você tem lindos e coloridos componentes UI!

e9835d65d6dd0634.png

Screenshot: Botões coloridos e visualização de texto

Sobre o estilo padrão

Você acabou de criar um arquivo de layout personalizado e referenciou-o usando controller_layout_id em activity_player.xml.

Outra abordagem é sobrepor o arquivo de layout padrão que PlayerControlView usa. O código fonte de PlayerControlView nos diz que ele usa R.layout.exo_player_control_view para layout. Se criar o nosso próprio ficheiro de layout com o mesmo nome de ficheiro, o ficheiro PlayerControlView utiliza o seu ficheiro em vez disso.

  1. Remover o atributo controller_layout_id que acabou de adicionar.
  2. Eliminar o ficheiro custom_player_control_view.xml.

O ficheiro PlayerView em activity_player.xml deve agora ter o seguinte aspecto:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
  1. Criar um ficheiro chamado exo_player_control_view.xml na pasta res/layout do módulo da sua biblioteca player-lib.
  2. Inserir o seguinte código em exo_player_control_view.xml para adicionar um botão play, um botão de pausa, e um ImageView com um logótipo:

exo_player**_control_view.xml***

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layoutDirection="ltr" android:background="#CC000000" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="4dp" android:orientation="horizontal"> <ImageButton android:id="@id/exo_play" style="@style/ExoMediaButton.Play"/> <ImageButton android:id="@id/exo_pause" style="@style/ExoMediaButton.Pause"/> </LinearLayout> <ImageView android:contentDescription="@string/logo" android:src="@drawable/google_logo" android:layout_width="match_parent" android:layout_height="wrap_content"/></LinearLayout>

Isto demonstra como pode adicionar os seus próprios elementos aqui e misturá-los com elementos de controlo padrão. ExoPlayerView agora usa o seu controlo personalizado e toda a lógica para esconder e mostrar quando interagir com o controlo é preservada.

Congratulações! Você aprendeu muito sobre a integração do ExoPlayer com seu app.

Saiba mais

Deixe uma resposta

O seu endereço de email não será publicado.