Como detectar eventos de reprodução
Eventos como mudanças de estado e erros de reprodução são informados aos usuários registrados
Instâncias de Player.Listener
. Registrar um listener para receber esses
eventos:
Kotlin
// Add a listener to receive events from the player. player.addListener(listener)
Java
// Add a listener to receive events from the player. player.addListener(listener);
A Player.Listener
tem métodos padrão vazios, então você só precisa implementar
os métodos em que você tem interesse. Consulte o Javadoc para ver uma descrição completa dos
os métodos e quando eles são chamados. Alguns dos métodos mais importantes são
descritos em mais detalhes abaixo.
As escutas têm a opção de implementar callbacks de eventos individuais ou
callback genérico onEvents
que é chamado após a ocorrência de um ou mais eventos.
juntas. Consulte Individual callbacks vs onEvents
para uma explicação sobre qual
em diferentes casos de uso.
Mudanças no estado de reprodução
As alterações no estado do player podem ser recebidas implementando
onPlaybackStateChanged(@State int state)
em um registro
Player.Listener
. O player pode estar em um dos quatro estados de reprodução:
Player.STATE_IDLE
: este é o estado inicial, quando o player é parou e quando a reprodução falhou. O jogador terá apenas recursos limitados nesse estado.Player.STATE_BUFFERING
: o player não pode começar imediatamente a partir do próprio posição atual. Isso acontece principalmente porque é preciso carregar mais dados.Player.STATE_READY
: o player pode reproduzir imediatamente a partir do posiçãoPlayer.STATE_ENDED
: o player terminou de reproduzir todas as mídias.
Além desses estados, o jogador tem uma flag playWhenReady
para indicar
a intenção do usuário de jogar. As mudanças nessa flag podem ser recebidas implementando
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
:
Um player está tocando (ou seja, sua posição está avançando e a mídia está sendo apresentadas ao usuário) quando todas as três condições a seguir forem atendidas:
- O player está no estado
Player.STATE_READY
. playWhenReady
étrue
- A reprodução não é suprimida pelo motivo retornado pelo
Player.getPlaybackSuppressionReason
Em vez de ter que verificar essas propriedades individualmente, Player.isPlaying
pode ser chamado. Alterações nesse estado podem ser recebidas implementando
onIsPlayingChanged(boolean isPlaying)
:
Kotlin
player.addListener( object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.playWhenReady, // player.playbackState, player.playbackSuppressionReason and // player.playerError for details. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onIsPlayingChanged(boolean isPlaying) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.getPlayWhenReady, // player.getPlaybackState, player.getPlaybackSuppressionReason and // player.getPlaybackError for details. } } });
Erros de reprodução
Os erros que causam falha na reprodução podem ser recebidos implementando
onPlayerError(PlaybackException error)
em um registro
Player.Listener
. Em caso de falha, este método será chamado
imediatamente antes da transição do estado de reprodução para Player.STATE_IDLE
.
Para tentar novamente as reproduções com falha ou interrompidas, chame ExoPlayer.prepare
.
Algumas implementações de Player
transmitem instâncias de subclasses de
PlaybackException
para fornecer mais informações sobre a falha. Para
exemplo, ExoPlayer
passa ExoPlaybackException
, que tem type
,
rendererIndex
e outros campos específicos do ExoPlayer.
O exemplo a seguir mostra como detectar quando uma reprodução falhou devido a um Problema de rede HTTP:
Kotlin
player.addListener( object : Player.Listener { override fun onPlayerError(error: PlaybackException) { val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. val httpError = cause // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError is InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } } )
Java
player.addListener( new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { @Nullable Throwable cause = error.getCause(); if (cause instanceof HttpDataSourceException) { // An HTTP error occurred. HttpDataSourceException httpError = (HttpDataSourceException) cause; // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError instanceof HttpDataSource.InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } });
Transições de playlists
sempre que o player mudar para um novo item de mídia na playlist.
onMediaItemTransition(MediaItem mediaItem,
@MediaItemTransitionReason int reason)
é chamado no estado registrado
objetos Player.Listener
. O motivo indica se este foi um processo
transição, uma busca (por exemplo, depois de chamar player.next()
), uma repetição de
o mesmo item ou por uma mudança na playlist (por exemplo, se o evento
o item em reprodução é removido).
Metadados
Os metadados retornados de player.getCurrentMediaMetadata()
podem mudar devido a muitos
motivos: transições de listas de reprodução, atualizações de metadados in-stream ou atualização do
MediaItem
no meio da reprodução atual.
Se você estiver interessado em alterações de metadados, por exemplo, para atualizar uma interface que mostra
o título atual, você pode ouvir onMediaMetadataChanged
.
Procurando
Chamar métodos Player.seekTo
resulta em uma série de callbacks para registros
Player.Listener
instâncias:
onPositionDiscontinuity
comreason=DISCONTINUITY_REASON_SEEK
. Isso é o resultado direto da chamada dePlayer.seekTo
. O callback temPositionInfo
para a posição antes e depois da busca.onPlaybackStateChanged
por qualquer mudança imediata de estado relacionada à busca. Talvez não haja essa mudança.
Callbacks individuais x onEvents
Os listeners podem escolher entre implementar callbacks individuais, como
onIsPlayingChanged(boolean isPlaying)
, e a abordagem genérica
onEvents(Player player, Events events)
. A chamada de retorno genérica fornece
acesso ao objeto Player
e especifica o conjunto de events
que ocorreu
juntas. Esse retorno de chamada é sempre chamado após os callbacks que correspondem ao
os eventos individuais.
Kotlin
override fun onEvents(player: Player, events: Player.Events) { if ( events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) ) { uiModule.updateUi(player) } }
Java
@Override public void onEvents(Player player, Events events) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { uiModule.updateUi(player); } }
É recomendável dar preferência a eventos individuais nos seguintes casos:
- O listener está interessado nos motivos das alterações. Por exemplo, o
motivos fornecidos para
onPlayWhenReadyChanged
ouonMediaItemTransition
. - O listener só atua sobre os novos valores fornecidos pelos parâmetros de callback ou aciona outra coisa que não dependa dos parâmetros de callback.
- A implementação do listener prefere uma indicação clara e legível do que acionou o evento no nome do método.
- O ouvinte se reporta a um sistema analítico que precisa saber tudo eventos individuais e alterações de estado.
O onEvents(Player player, Events events)
genérico tem preferência na
seguintes casos:
- O listener quer acionar a mesma lógica para vários eventos. Para
exemplo, atualizar uma IU para
onPlaybackStateChanged
eonPlayWhenReadyChanged
. - O listener precisa acessar o objeto
Player
para acionar outros eventos. por exemplo, busca após uma transição de item de mídia. - O listener pretende usar vários valores de estado que são relatados
usando callbacks separados ou em combinação com o getter
Player
. métodos. Por exemplo, usarPlayer.getCurrentWindowIndex()
com o OTimeline
informado noonTimelineChanged
só é seguro noonEvents
. - O listener está interessado em saber se os eventos ocorreram logicamente juntos. Para
exemplo, de
onPlaybackStateChanged
aSTATE_BUFFERING
devido a um item de mídia a transição.
Em alguns casos, os listeners podem precisar combinar os callbacks individuais com o
callback onEvents
genérico, por exemplo, para registrar os motivos de mudança do item de mídia.
com onMediaItemTransition
, mas só atuam quando todas as mudanças de estado podem ser usadas
em onEvents
.
Como usar o AnalyticsListener
Ao usar ExoPlayer
, um AnalyticsListener
pode ser registrado com o jogador
chame addAnalyticsListener
. AnalyticsListener
implementações podem
para detectar eventos detalhados que podem ser úteis para análises e registros
propósitos. Consulte a página de análises para mais detalhes.
Como usar o EventLogger
EventLogger
é um AnalyticsListener
fornecido diretamente pela biblioteca para
para fins de geração de registros. Adicionar EventLogger
a um ExoPlayer
para ativar métricas
geração de registros adicional com uma única linha:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Consulte a página de geração de registros de depuração para saber mais.
Disparar eventos em posições de reprodução específicas
Alguns casos de uso exigem o disparo de eventos em posições de reprodução especificadas. Isso é
compatível com o uso de PlayerMessage
. Um PlayerMessage
pode ser criado usando
ExoPlayer.createMessage
. A posição de reprodução em que ele deve ser executado
podem ser definidas usando PlayerMessage.setPosition
. As mensagens são executadas
sequência de reprodução por padrão, mas isso pode ser personalizado usando
PlayerMessage.setLooper
: PlayerMessage.setDeleteAfterDelivery
pode ser usado
para controlar se a mensagem será executada sempre que a mensagem
posição de reprodução for encontrada (isso pode acontecer várias vezes devido à busca
e repetir) ou apenas na primeira vez. Quando o PlayerMessage
for
configurado, ele pode ser programado usando PlayerMessage.send
.
Kotlin
player .createMessage { messageType: Int, payload: Any? -> } .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send()
Java
player .createMessage( (messageType, payload) -> { // Do something at the specified playback position. }) .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send();