Acara pemain

Memproses peristiwa pemutaran

Peristiwa, seperti perubahan status dan error pemutaran, dilaporkan ke Instance Player.Listener. Untuk mendaftarkan pemroses guna menerima acara:

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 memiliki metode default kosong sehingga Anda hanya perlu mengimplementasikan metode yang Anda minati. Lihat Javadoc untuk deskripsi lengkap tentang metode dan kapan metode tersebut dipanggil. Beberapa metode yang paling penting adalah yang dijelaskan secara lebih detail di bawah ini.

Pemroses memiliki pilihan antara menerapkan callback peristiwa individual atau Callback onEvents generik yang dipanggil setelah satu atau beberapa peristiwa terjadi secara bersamaan. Lihat Individual callbacks vs onEvents untuk penjelasannya harus dipilih untuk kasus penggunaan yang berbeda.

Perubahan status pemutaran

Perubahan pada status pemutar dapat diterima dengan mengimplementasikan onPlaybackStateChanged(@State int state) terdaftar Player.Listener. Pemutar dapat berada dalam salah satu dari empat status pemutaran:

  • Player.STATE_IDLE: Ini adalah status awal, yaitu status saat pemutar video dihentikan, dan saat pemutaran gagal. Pemain hanya akan memiliki sumber daya terbatas status ini.
  • Player.STATE_BUFFERING: Pemain tidak dapat langsung bermain dari posisi saat ini. Hal ini umumnya terjadi karena ada lebih banyak data yang perlu dimuat.
  • Player.STATE_READY: Pemain dapat langsung memutar dari tempatnya saat ini posisi Anda.
  • Player.STATE_ENDED: Pemutar selesai memutar semua media.

Selain status ini, pemutar memiliki flag playWhenReady untuk menunjukkan maksud pengguna untuk bermain. Perubahan pada tanda ini dapat diterima dengan menerapkan onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason).

Pemain sedang memutar (posisinya sedang naik daun dan media sedang ditampilkan kepada pengguna) jika ketiga kondisi berikut terpenuhi:

  • Pemutar dalam status Player.STATE_READY
  • playWhenReady adalah true
  • Pemutaran tidak dihentikan karena alasan yang ditampilkan oleh Player.getPlaybackSuppressionReason

Player.isPlaying tidak harus memeriksa properti ini satu per satu dapat dipanggil. Perubahan pada status ini dapat diterima dengan menerapkan 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.
        }
      }
    });

Error saat pemutaran

Error yang menyebabkan pemutaran gagal dapat diterima dengan menerapkan onPlayerError(PlaybackException error) terdaftar Player.Listener. Jika terjadi kegagalan, metode ini akan dipanggil tepat sebelum status pemutaran bertransisi menjadi Player.STATE_IDLE. Pemutaran yang gagal atau dihentikan dapat dicoba lagi dengan memanggil ExoPlayer.prepare.

Perlu diperhatikan bahwa beberapa implementasi Player meneruskan instance subclass dari PlaybackException untuk memberikan informasi tambahan tentang kegagalan. Sebagai contoh, ExoPlayer meneruskan ExoPlaybackException, yang memiliki type, rendererIndex, dan kolom khusus ExoPlayer lainnya.

Contoh berikut menunjukkan cara mendeteksi bila pemutaran gagal karena Masalah jaringan 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.
          }
        }
      }
    });

Transisi playlist

Setiap kali pemutar berubah ke item media baru dalam playlist onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) dipanggil saat terdaftar Player.Listener objek. Alasannya menunjukkan apakah tindakan ini transisi, pencarian (misalnya setelah memanggil player.next()), pengulangan item yang sama, atau disebabkan oleh perubahan playlist (misalnya, jika saat ini item yang diputar akan dihapus).

Metadata

Metadata yang ditampilkan dari player.getCurrentMediaMetadata() dapat berubah karena banyak alasan: transisi playlist, pembaruan metadata in-stream, atau pembaruan MediaItem saat ini di tengah pemutaran.

Jika Anda tertarik dengan perubahan metadata, misalnya untuk memperbarui UI yang menampilkan judul saat ini, Anda dapat mendengarkan onMediaMetadataChanged.

Mencari

Memanggil metode Player.seekTo akan menghasilkan serangkaian callback yang didaftarkan Player.Listener instance:

  1. onPositionDiscontinuity dengan reason=DISCONTINUITY_REASON_SEEK. Ini adalah hasil langsung dari panggilan Player.seekTo. Callback memiliki PositionInfo {i>field <i}untuk posisi sebelum dan sesudah pencarian.
  2. onPlaybackStateChanged dengan perubahan status langsung yang terkait dengan pencarian. Perhatikan bahwa mungkin tidak ada perubahan tersebut.

Callback individual versus onEvents

Pemroses bisa memilih antara mengimplementasikan callback individual seperti onIsPlayingChanged(boolean isPlaying), dan generik Callback onEvents(Player player, Events events). Callback generik menyediakan akses ke objek Player dan menentukan kumpulan events yang terjadi secara bersamaan. Callback ini selalu dipanggil setelah callback yang sesuai dengan setiap peristiwa.

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

Peristiwa individual harus lebih disarankan dalam kasus berikut:

  • Pemroses ingin mengetahui alasan perubahan. Misalnya, alasan yang diberikan untuk onPlayWhenReadyChanged atau onMediaItemTransition.
  • Pemroses hanya bertindak pada nilai baru yang disediakan melalui parameter callback atau memicu hal lain yang tidak bergantung pada parameter callback.
  • Implementasi pemroses lebih memilih indikasi yang jelas dapat dibaca tentang apa memicu peristiwa dalam nama metode.
  • Pemroses melapor ke sistem analisis yang perlu mengetahui semua peristiwa individual dan perubahan status.

onEvents(Player player, Events events) generik harus dipilih di kasus berikut:

  • Pemroses ingin memicu logika yang sama untuk beberapa peristiwa. Sebagai misalnya mengupdate UI untuk onPlaybackStateChanged dan onPlayWhenReadyChanged.
  • Pemroses memerlukan akses objek Player untuk memicu peristiwa lebih lanjut, misalnya pencarian setelah transisi item media.
  • Pemroses bermaksud menggunakan beberapa nilai status yang dilaporkan melalui callback terpisah bersama-sama, atau dikombinasikan dengan pengambil Player metode. Misalnya, menggunakan Player.getCurrentWindowIndex() dengan Timeline yang disediakan di onTimelineChanged hanya aman dari dalam Callback onEvents.
  • Pemroses ingin mengetahui apakah peristiwa secara logis terjadi bersama-sama. Sebagai misalnya, onPlaybackStateChanged menjadi STATE_BUFFERING karena item media transisi.

Dalam beberapa kasus, pemroses mungkin perlu menggabungkan masing-masing callback dengan Callback onEvents generik, misalnya untuk merekam alasan perubahan item media dengan onMediaItemTransition, tetapi hanya bertindak setelah semua perubahan status dapat digunakan bersama-sama di onEvents.

Menggunakan AnalyticsListener

Saat menggunakan ExoPlayer, AnalyticsListener dapat didaftarkan dengan pemutar dengan memanggil addAnalyticsListener. Implementasi AnalyticsListener dapat peristiwa mendetail yang mungkin berguna untuk analisis dan logging tujuan. Lihat halaman analisis untuk mengetahui detail selengkapnya.

Menggunakan EventLogger

EventLogger adalah AnalyticsListener yang disediakan langsung oleh library untuk tujuan logging. Tambahkan EventLogger ke ExoPlayer untuk mengaktifkan fungsi logging tambahan dengan satu baris:

Kotlin

player.addAnalyticsListener(EventLogger())

Java

player.addAnalyticsListener(new EventLogger());

Lihat halaman logging debug untuk mengetahui detail selengkapnya.

Peristiwa pengaktifan pada posisi pemutaran yang ditentukan

Beberapa kasus penggunaan memerlukan pengaktifan peristiwa pada posisi pemutaran yang ditentukan. Ini adalah didukung menggunakan PlayerMessage. PlayerMessage dapat dibuat menggunakan ExoPlayer.createMessage. Posisi pemutaran tempat eksekusi harus dijalankan dapat disetel menggunakan PlayerMessage.setPosition. Pesan dieksekusi pada secara default, tetapi dapat disesuaikan menggunakan PlayerMessage.setLooper. PlayerMessage.setDeleteAfterDelivery dapat digunakan untuk mengontrol apakah pesan akan dieksekusi setiap kali panggilan posisi pemutaran ditemui (ini dapat terjadi beberapa kali karena pencarian dan mode ulangi), atau hanya saat pertama kali. Setelah PlayerMessage dikonfigurasi, dapat dijadwalkan menggunakan 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();