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
adalahtrue
- 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:
onPositionDiscontinuity
denganreason=DISCONTINUITY_REASON_SEEK
. Ini adalah hasil langsung dari panggilanPlayer.seekTo
. Callback memilikiPositionInfo
{i>field <i}untuk posisi sebelum dan sesudah pencarian.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
atauonMediaItemTransition
. - 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
danonPlayWhenReadyChanged
. - 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, menggunakanPlayer.getCurrentWindowIndex()
denganTimeline
yang disediakan dionTimelineChanged
hanya aman dari dalam CallbackonEvents
. - Pemroses ingin mengetahui apakah peristiwa secara logis terjadi bersama-sama. Sebagai
misalnya,
onPlaybackStateChanged
menjadiSTATE_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();