Ascolto di eventi di riproduzione
Gli eventi, come le variazioni di stato e gli errori di riproduzione, vengono segnalati alle istanze Player.Listener
registrate. Per registrare un ascoltatore che riceva 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 Javadoc per una descrizione completa dei metodi e quando vengono chiamati. Alcuni dei metodi più importanti sono
descritti più dettagliatamente di seguito.
I listener possono scegliere tra l'implementazione di callback di singoli eventi o un callback onEvents
generico che viene chiamato dopo che si verificano uno o più eventi insieme. Consulta la pagina Individual callbacks vs onEvents
per una spiegazione di quali soluzioni dovrebbero essere preferite 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ò avere uno dei quattro stati di riproduzione disponibili:
Player.STATE_IDLE
: questo è lo stato iniziale, lo stato in cui il player viene interrotto e quando la riproduzione non è riuscita. In questo stato, il player conserverà solo risorse limitate.Player.STATE_BUFFERING
: il player non è in grado di riprodurre immediatamente dalla posizione corrente. Ciò avviene principalmente perché è necessario caricare più dati.Player.STATE_READY
: il player è in grado di riprodurre immediatamente dalla sua posizione corrente.Player.STATE_ENDED
: il player ha terminato la riproduzione di tutti i contenuti multimediali.
Oltre a questi stati, il player ha un flag playWhenReady
che indica
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 il contenuto multimediale viene presentato all'utente) quando sono soddisfatte tutte e tre le seguenti condizioni:
- Il player è nello stato
Player.STATE_READY
playWhenReady
ètrue
- La riproduzione non viene soppressa per un motivo restituito da
Player.getPlaybackSuppressionReason
Anziché controllare singolarmente queste proprietà, è 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 la mancata riuscita della riproduzione possono essere ricevuti implementando onPlayerError(PlaybackException error)
in un Player.Listener
registrato. In caso di errore, questo metodo viene chiamato
subito prima che lo stato di riproduzione passi a Player.STATE_IDLE
.
È possibile riprovare a riprodurre le riproduzioni non riuscite o interrotte chiamando il numero ExoPlayer.prepare
.
Tieni presente che alcune implementazioni Player
superano le istanze delle sottoclassi di PlaybackException
per fornire ulteriori informazioni sull'errore. Ad
esempio, ExoPlayer
passa ExoPlaybackException
, che ha type
,
rendererIndex
e altri campi specifici di ExoPlayer.
L'esempio seguente mostra come rilevare quando una 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 delle playlist
Ogni volta che il player passa a un nuovo elemento multimediale nella playlist
onMediaItemTransition(MediaItem mediaItem,
@MediaItemTransitionReason int reason)
viene richiamato sugli oggetti
Player.Listener
registrati. Il motivo indica se si tratta di una transizione automatica, una ricerca (ad esempio dopo la chiamata a player.next()
), una ripetizione dello stesso elemento o una modifica di una playlist (ad esempio, se l'elemento attualmente in riproduzione viene rimosso).
Metadati
I metadati restituiti da player.getCurrentMediaMetadata()
possono cambiare per diversi motivi: transizioni alle playlist, aggiornamenti dei metadati in-stream o aggiornamento dell'attuale riproduzione di MediaItem
durante la riproduzione.
Se vuoi apportare modifiche ai metadati, ad esempio per aggiornare una UI che mostra
il titolo corrente, puoi ascoltare onMediaMetadataChanged
.
Attivazione dello spostamento in corso
La chiamata dei metodi Player.seekTo
genera una serie di callback alle istanze Player.Listener
registrate:
onPositionDiscontinuity
conreason=DISCONTINUITY_REASON_SEEK
. Questo è il risultato diretto della chiamata aPlayer.seekTo
. Il callback haPositionInfo
campi per la posizione prima e dopo la ricerca.onPlaybackStateChanged
con qualsiasi modifica immediata dello stato relativa alla ricerca. Tieni presente che questo cambiamento potrebbe non essere presente.
Confronto tra chiamate individuali e onEvents
I listener possono scegliere tra l'implementazione di singoli callback come onIsPlayingChanged(boolean isPlaying)
e il callback onEvents(Player player, Events events)
generico. Il callback generico consente di accedere all'oggetto Player
e specifica il set 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); } }
È consigliabile preferire i singoli eventi nei seguenti casi:
- L'ascoltatore è interessato ai motivi delle modifiche. Ad esempio, i
motivi forniti per
onPlayWhenReadyChanged
oonMediaItemTransition
. - 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 a un sistema di analisi che deve conoscere tutti i singoli eventi e le modifiche dello stato.
Il valore onEvents(Player player, Events events)
generico dovrebbe essere preferibile nei seguenti casi:
- Il listener vuole attivare la stessa logica per più eventi. Ad esempio, l'aggiornamento di una UI sia per
onPlaybackStateChanged
sia peronPlayWhenReadyChanged
. - Il listener deve accedere all'oggetto
Player
per 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, puoi usarePlayer.getCurrentWindowIndex()
conTimeline
fornito inonTimelineChanged
solo all'interno del callbackonEvents
. - Il listener vuole sapere se gli eventi si sono verificati insieme logicamente. Ad esempio,
onPlaybackStateChanged
inSTATE_BUFFERING
a causa della transizione di un elemento multimediale.
In alcuni casi, i listener potrebbero dover combinare i singoli callback con il callback onEvents
generico, ad esempio per registrare i motivi della modifica degli elementi multimediali con onMediaItemTransition
, ma agire solo quando tutte le modifiche di stato possono essere utilizzate insieme in onEvents
.
In uso: AnalyticsListener
Quando utilizzi ExoPlayer
, è possibile registrare un AnalyticsListener
con il player
chiamando addAnalyticsListener
. Le implementazioni AnalyticsListener
sono in grado di ascoltare eventi dettagliati che possono essere utili per scopi di analisi e logging. Per ulteriori dettagli, consulta la pagina dei dati e analisi.
In uso: EventLogger
EventLogger
è un AnalyticsListener
fornito direttamente dalla libreria ai fini del logging. Aggiungi EventLogger
a un ExoPlayer
per consentire log aggiuntivi utili con una sola riga:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Per ulteriori dettagli, consulta la pagina del logging di debug.
Attivazione di eventi in posizioni di riproduzione specificate
Alcuni casi d'uso richiedono l'attivazione di eventi in posizioni di riproduzione specificate. Questa operazione è supportata utilizzando PlayerMessage
. È possibile creare un PlayerMessage
utilizzando
ExoPlayer.createMessage
. La posizione di riproduzione in cui deve essere eseguita
può essere impostata utilizzando PlayerMessage.setPosition
. Per impostazione predefinita, i messaggi vengono eseguiti nel thread di riproduzione, ma è possibile personalizzarli 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 (questo può accadere più volte a causa delle modalità di ricerca e ripetizione) o solo la prima volta. Una volta configurato PlayerMessage
, puoi pianificarlo 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();