Événements du joueur

Écouter des événements de lecture

Les événements, tels que les changements d'état et les erreurs de lecture, sont signalés aux Instances Player.Listener. Pour enregistrer un écouteur afin de recevoir événements:

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 comporte des méthodes par défaut vides. Il vous suffit donc d'implémenter les méthodes qui vous intéressent. Consultez la documentation Javadoc pour obtenir une description complète de les méthodes et le moment où elles sont appelées. Certaines des méthodes les plus importantes sont décrits plus en détail ci-dessous.

Les écouteurs ont le choix entre implémenter des rappels d'événements individuels ou un rappel onEvents générique, appelé après qu'un ou plusieurs événements se sont produits ; ensemble. Consultez la section Individual callbacks vs onEvents pour savoir quelles sont à privilégier selon les cas d'utilisation.

Changements de l'état de lecture

Vous pouvez recevoir des changements d'état du lecteur en implémentant onPlaybackStateChanged(@State int state) dans un compte enregistré Player.Listener L'un des quatre états de lecture suivants est disponible:

  • Player.STATE_IDLE: il s'agit de l'état initial, c'est-à-dire de l'état lorsque le lecteur est et quand la lecture a échoué. Le lecteur ne contiendra que des ressources limitées dans cet état.
  • Player.STATE_BUFFERING: le lecteur ne peut pas lancer immédiatement la lecture depuis son position actuelle. Cela se produit principalement parce que davantage de données doivent être chargées.
  • Player.STATE_READY: le lecteur est en mesure de lire immédiatement la position de votre annonce.
  • Player.STATE_ENDED: le lecteur a fini de lire tous les contenus multimédias.

En plus de ces états, le joueur dispose d'un indicateur playWhenReady pour indiquer l'intention de jouer de l'utilisateur. Vous pouvez recevoir les modifications apportées à cet indicateur en implémentant onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)

Un lecteur est en cours de lecture (sa position progresse et le contenu multimédia est en cours de lecture). présenté à l'utilisateur) lorsque les trois conditions suivantes sont remplies:

  • Le lecteur est à l'état Player.STATE_READY.
  • playWhenReady est true
  • La lecture n'est pas interrompue pour un motif renvoyé par Player.getPlaybackSuppressionReason

Plutôt que de vérifier ces propriétés individuellement, Player.isPlaying peut être appelé. Vous pouvez recevoir les modifications apportées à cet état en implémentant 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.
        }
      }
    });

Erreurs de lecture

Les erreurs entraînant l'échec de la lecture peuvent être reçues en implémentant onPlayerError(PlaybackException error) dans un compte enregistré Player.Listener En cas d'échec, cette méthode est appelée immédiatement avant que l'état de lecture ne passe à Player.STATE_IDLE. Vous pouvez relancer les lectures ayant échoué ou interrompues en appelant ExoPlayer.prepare.

Notez que certaines implémentations Player transmettent des instances de sous-classes de PlaybackException pour fournir des informations supplémentaires sur l'échec. Pour par exemple, ExoPlayer transmet ExoPlaybackException, qui contient type, rendererIndex et d'autres champs spécifiques à ExoPlayer.

L'exemple suivant montre comment détecter les échecs de lecture liés à une Problème de réseau 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.
          }
        }
      }
    });

Transitions de playlist

Chaque fois que le lecteur passe à un nouvel élément multimédia dans la playlist. La méthode onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) est appelée sur une adresse e-mail enregistrée Objets Player.Listener. La raison indique s'il s'agit d'un une transition, une recherche (par exemple, après avoir appelé player.next()), une répétition de le même élément ou en raison d'une modification de la playlist (par exemple, si le de l'élément en cours de lecture a été supprimé).

Métadonnées

Les métadonnées renvoyées par player.getCurrentMediaMetadata() peuvent changer raisons: des transitions de playlists, des mises à jour des métadonnées InStream ou des modifications MediaItem en cours de lecture.

Si vous êtes intéressé par les modifications de métadonnées, par exemple pour mettre à jour une UI qui affiche le titre actuel, vous pouvez écouter onMediaMetadataChanged.

Recherche…

L'appel de méthodes Player.seekTo entraîne une série de rappels aux méthodes enregistrées Instances Player.Listener:

  1. onPositionDiscontinuity avec reason=DISCONTINUITY_REASON_SEEK. C'est le résultat direct de l'appel de Player.seekTo. Le rappel comporte PositionInfo pour la position avant et après la recherche.
  2. onPlaybackStateChanged avec tout changement d'état immédiat lié à la recherche. Notez que ce n'est peut-être pas le cas.

Rappels individuels et onEvents

Les écouteurs peuvent choisir d'implémenter des rappels individuels tels que onIsPlayingChanged(boolean isPlaying) et l'argument générique Rappel onEvents(Player player, Events events). Le rappel générique fournit l'accès à l'objet Player et spécifie l'ensemble des events qui ont eu lieu ensemble. Ce rappel est toujours appelé après les rappels qui correspondent à les événements individuels.

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);
  }
}

Des événements individuels doivent être privilégiés dans les cas suivants:

  • L'écouteur s'intéresse aux raisons des modifications. Par exemple, motifs indiqués pour onPlayWhenReadyChanged ou onMediaItemTransition.
  • L'écouteur n'agit que sur les nouvelles valeurs fournies via des paramètres de rappel ou déclenche autre chose qui ne dépend pas des paramètres de rappel.
  • L'implémentation de l'écouteur préfère une indication claire et lisible déclenché l'événement dans le nom de la méthode.
  • L'écouteur est transmis à un système d'analyse qui doit connaître des événements individuels et des changements d'état.

Il est préférable d'utiliser le onEvents(Player player, Events events) générique dans les cas suivants:

  • L'écouteur souhaite déclencher la même logique pour plusieurs événements. Pour exemple, la mise à jour d'une UI pour onPlaybackStateChanged et onPlayWhenReadyChanged
  • L'écouteur a besoin d'accéder à l'objet Player pour déclencher d'autres événements. par exemple la recherche après la transition d'un élément multimédia.
  • L'écouteur a l'intention d'utiliser plusieurs valeurs d'état via des rappels distincts ou en combinaison avec le getter Player. méthodes. Par exemple, si vous utilisez Player.getCurrentWindowIndex() avec Le champ Timeline fourni dans onTimelineChanged n'est sécurisé qu'à partir du Rappel onEvents.
  • L'écouteur souhaite savoir si les événements se sont produits de manière logique ensemble. Pour Exemple : de onPlaybackStateChanged à STATE_BUFFERING en raison d'un élément multimédia transition.

Dans certains cas, les écouteurs peuvent avoir besoin de combiner les rappels individuels avec la méthode Rappel onEvents générique, par exemple pour enregistrer les motifs de modification de l'élément multimédia avec onMediaItemTransition, mais n'agir qu'une fois que tous les changements d'état peuvent être utilisés ensemble dans onEvents.

AnalyticsListener utilisé(s)

Lorsque vous utilisez ExoPlayer, un AnalyticsListener peut être enregistré auprès du joueur en appelant addAnalyticsListener. Les implémentations AnalyticsListener peuvent pour écouter des événements détaillés pouvant être utiles pour l'analyse et la journalisation objectifs. Pour en savoir plus, consultez la page Données analytiques.

EventLogger utilisé(s)

EventLogger est un AnalyticsListener fourni directement par la bibliothèque pour à des fins de journalisation. Ajoutez EventLogger à une ExoPlayer pour l'activer d'une journalisation supplémentaire sur une seule ligne:

Kotlin

player.addAnalyticsListener(EventLogger())

Java

player.addAnalyticsListener(new EventLogger());

Pour en savoir plus, consultez la page de journalisation du débogage.

Déclenchement d'événements au niveau des positions de lecture spécifiées

Certains cas d'utilisation nécessitent le déclenchement d'événements au niveau des positions de lecture spécifiées. C'est compatible avec PlayerMessage. Vous pouvez créer un PlayerMessage à l'aide de ExoPlayer.createMessage Position de lecture à laquelle l'application doit être exécutée peut être défini à l'aide de PlayerMessage.setPosition. Les messages sont exécutés thread par défaut, mais vous pouvez le personnaliser avec PlayerMessage.setLooper Vous pouvez utiliser PlayerMessage.setDeleteAfterDelivery pour déterminer si le message sera exécuté à chaque fois que la valeur Position de lecture trouvée (cela peut se produire plusieurs fois en raison de la recherche) et de répétition) ou la première fois. Une fois que PlayerMessage est configurée, elle peut être planifiée à l'aide de 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();