Ascolto degli eventi di riproduzione
Gli eventi, come le modifiche dello stato e gli errori di riproduzione, vengono segnalati alle istanze Player.Listener registrate. Per registrare un listener per ricevere questi eventi:
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);
Player.Listener ha metodi predefiniti vuoti, quindi devi implementare solo i metodi che ti interessano. Consulta la documentazione Javadoc per una descrizione completa dei metodi e di quando vengono chiamati. Alcuni dei metodi più importanti sono
descritti in dettaglio di seguito.
Gli ascoltatori possono scegliere tra l'implementazione di callback di eventi individuali o un callback onEvents generico chiamato dopo che si sono verificati uno o più eventi insieme. Consulta Individual callbacks vs onEvents per una spiegazione di quale
deve essere preferito per i diversi casi d'uso.
Modifiche dello stato di riproduzione
Le modifiche allo stato del player possono essere ricevute implementando
onPlaybackStateChanged(@State int state) in un Player.Listener registrato.
Il player può trovarsi in uno dei quattro stati di riproduzione:
Player.STATE_IDLE: è lo stato iniziale, lo stato in cui il giocatore è in pausa e quando la riproduzione non è riuscita. In questo stato, il giocatore conterrà solo risorse limitate.Player.STATE_BUFFERING: Il lettore non è in grado di riprodurre immediatamente dalla posizione attuale. Ciò accade principalmente perché è necessario caricare più dati.Player.STATE_READY: Il lettore è in grado di riprodurre immediatamente dalla posizione corrente.Player.STATE_ENDED: Il lettore ha terminato la riproduzione di tutti i contenuti multimediali.
Oltre a questi stati, il giocatore ha un flag playWhenReady per indicare
l'intenzione dell'utente di giocare. Le modifiche a questo flag possono essere ricevute implementando
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason).
Un player è in riproduzione (ovvero la sua posizione sta avanzando e i contenuti multimediali vengono presentati all'utente) quando sono soddisfatte tutte e tre le seguenti condizioni:
- Il player è nello stato
Player.STATE_READY playWhenReadyètrue- La riproduzione non è soppressa per un motivo restituito da
Player.getPlaybackSuppressionReason
Anziché dover controllare queste proprietà singolarmente, è possibile chiamare Player.isPlaying. Le modifiche a questo stato possono essere ricevute 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. } } });
Errori di riproduzione
Gli errori che causano il fallimento della riproduzione possono essere ricevuti implementando
onPlayerError(PlaybackException error) in un Player.Listener registrato. Quando
si verifica un errore, questo metodo viene chiamato immediatamente prima che lo stato di riproduzione
passi a Player.STATE_IDLE. Le riproduzioni non riuscite o interrotte possono essere
riprovate chiamando il numero ExoPlayer.prepare.
Tieni presente che alcune implementazioni di Player passano istanze di sottoclassi di
PlaybackException per fornire ulteriori informazioni sull'errore. Ad esempio, ExoPlayer passa ExoPlaybackException, che contiene type,
rendererIndex e altri campi specifici di ExoPlayer.
L'esempio seguente mostra come rilevare quando la riproduzione non è riuscita a causa di un problema di rete 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. } } } });
Transizioni tra le playlist
Ogni volta che il player passa a un nuovo elemento multimediale nella playlist,
onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int
reason) viene chiamato sugli oggetti Player.Listener registrati. Il motivo indica
se si è trattato di una transizione automatica, di una ricerca (ad esempio dopo aver chiamato
player.next()), di una ripetizione dello stesso elemento o di una modifica della playlist
(ad esempio, se l'elemento attualmente in riproduzione viene rimosso).
Metadati
I metadati restituiti da player.getCurrentMediaMetadata() possono cambiare per molti motivi: transizioni delle playlist, aggiornamenti dei metadati in-stream o aggiornamento di MediaItem corrente a metà riproduzione.
Se ti interessano le modifiche ai metadati, ad esempio per aggiornare un'interfaccia utente che mostra
il titolo attuale, puoi ascoltare onMediaMetadataChanged.
Attivazione dello spostamento in corso
La chiamata ai metodi Player.seekTo genera una serie di callback alle istanze Player.Listener registrate:
onPositionDiscontinuityconreason=DISCONTINUITY_REASON_SEEK. Questo è il risultato diretto della chiamata aPlayer.seekTo. Il callback haPositionInfocampi per la posizione prima e dopo la ricerca.onPlaybackStateChangedcon qualsiasi cambiamento di stato immediato correlato alla ricerca. Tieni presente che potrebbe non esserci alcuna modifica.
Callback individuali e onEvents
Gli ascoltatori possono scegliere tra l'implementazione di callback individuali come
onIsPlayingChanged(boolean isPlaying) e il callback generico onEvents(Player
player, Events events). Il callback generico fornisce l'accesso all'oggetto
Player e specifica l'insieme di events che si sono verificati insieme. Questo
callback viene sempre chiamato dopo i callback corrispondenti ai singoli
eventi.
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); } }
Gli eventi individuali sono preferibili nei seguenti casi:
- L'ascoltatore è interessato ai motivi dei cambiamenti. Ad esempio, i motivi forniti per
onPlayWhenReadyChangedoonMediaItemTransition. - Il listener agisce solo sui nuovi valori forniti tramite i parametri di callback o attiva qualcos'altro che non dipende dai parametri di callback.
- L'implementazione del listener preferisce un'indicazione chiara e leggibile di ciò che ha attivato l'evento nel nome del metodo.
- Il listener genera report per un sistema di analisi che deve conoscere tutti i singoli eventi e le modifiche dello stato.
Il segnaposto generico onEvents(Player player, Events events) è preferibile nei seguenti casi:
- L'ascoltatore vuole attivare la stessa logica per più eventi. Ad
esempio, l'aggiornamento di un'interfaccia utente sia per
onPlaybackStateChangedsia peronPlayWhenReadyChanged. - Il listener deve accedere all'oggetto
Playerper attivare ulteriori eventi, ad esempio la ricerca dopo la transizione di un elemento multimediale. - Il listener intende utilizzare più valori di stato segnalati tramite
callback separati insieme o in combinazione con i metodi getter
Player. Ad esempio, l'utilizzo diPlayer.getCurrentWindowIndex()conTimelinefornito inonTimelineChangedè sicuro solo dall'interno del callbackonEvents. - Il listener è interessato a sapere se gli eventi si sono verificati logicamente insieme.
Ad esempio, da
onPlaybackStateChangedaSTATE_BUFFERINGa causa di una transizione di un elemento multimediale.
In alcuni casi, gli ascoltatori potrebbero dover combinare i singoli callback con il callback generico onEvents, ad esempio per registrare i motivi della modifica degli elementi multimediali con onMediaItemTransition, ma agire solo quando tutte le modifiche dello stato possono essere utilizzate insieme in onEvents.
In uso: AnalyticsListener
Quando si utilizza ExoPlayer, è possibile registrare un AnalyticsListener con il giocatore
chiamando addAnalyticsListener. Le implementazioni di AnalyticsListener sono in grado
di ascoltare eventi dettagliati che possono essere utili per l'analisi e la registrazione
dei log. Per maggiori dettagli, consulta la pagina di analisi.
In uso: EventLogger
EventLogger è un AnalyticsListener fornito direttamente dalla libreria per
scopi di logging. Aggiungi EventLogger a un ExoPlayer per attivare un logging aggiuntivo utile con una sola riga:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Per ulteriori dettagli, consulta la pagina di logging di debug.
Attivazione di eventi in posizioni di riproduzione specificate
Alcuni casi d'uso richiedono l'attivazione di eventi in posizioni di riproduzione specifiche. Questa operazione
è supportata tramite PlayerMessage. È possibile creare un PlayerMessage utilizzando
ExoPlayer.createMessage. La posizione di riproduzione in cui deve essere eseguito
può essere impostata utilizzando PlayerMessage.setPosition. I messaggi vengono eseguiti sul
thread di riproduzione per impostazione predefinita, ma possono essere personalizzati utilizzando
PlayerMessage.setLooper. PlayerMessage.setDeleteAfterDelivery può essere utilizzato per
controllare se il messaggio verrà eseguito ogni volta che viene raggiunta la posizione di riproduzione specificata (ciò può verificarsi più volte a causa delle modalità di ricerca e
ripetizione) o solo la prima volta. Una volta configurato PlayerMessage,
può essere pianificato utilizzando 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();