Memproses peristiwa pemutaran
Peristiwa, seperti perubahan status dan error pemutaran, dilaporkan ke instance
Player.Listener
yang terdaftar. Untuk mendaftarkan pemroses agar menerima peristiwa
tersebut:
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 diinginkan. Lihat Javadoc untuk mengetahui deskripsi lengkap
metode dan kapan metode tersebut dipanggil. Beberapa metode yang paling penting
dijelaskan secara lebih mendetail di bawah ini.
Pemroses memiliki pilihan antara menerapkan callback peristiwa individual atau callback onEvents
umum yang dipanggil setelah satu atau beberapa peristiwa terjadi bersama. Lihat Individual callbacks vs onEvents
untuk mengetahui penjelasan yang sebaiknya lebih diutamakan untuk berbagai kasus penggunaan.
Perubahan status pemutaran
Perubahan status pemain dapat diterima dengan menerapkan
onPlaybackStateChanged(@State int state)
dalam Player.Listener
yang terdaftar. Pemutar dapat berada dalam salah satu dari empat status pemutaran:
Player.STATE_IDLE
: Ini adalah status awal, status saat pemutar dihentikan, dan saat pemutaran gagal. Pemain hanya akan memiliki resource terbatas dalam status ini.Player.STATE_BUFFERING
: Pemutar tidak dapat langsung memutar dari posisinya saat ini. Hal ini terutama terjadi karena lebih banyak data yang perlu dimuat.Player.STATE_READY
: Pemutar dapat langsung memutar dari posisinya saat ini.Player.STATE_ENDED
: Pemutar selesai memutar semua media.
Selain status ini, pemain memiliki flag playWhenReady
untuk menunjukkan
niat pengguna untuk bermain. Perubahan dalam tanda ini dapat diterima dengan mengimplementasikan
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
.
Pemutar sedang diputar (yaitu, posisinya maju dan media ditampilkan kepada pengguna) saat ketiga kondisi berikut terpenuhi:
- Pemutar dalam status
Player.STATE_READY
playWhenReady
adalahtrue
- Pemutaran tidak dihentikan karena alasan yang ditampilkan oleh
Player.getPlaybackSuppressionReason
Daripada memeriksa properti tersebut satu per satu, Player.isPlaying
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 mengimplementasikan
onPlayerError(PlaybackException error)
dalam Player.Listener
yang terdaftar. Jika terjadi kegagalan, metode ini akan segera dipanggil sebelum status pemutaran bertransisi ke Player.STATE_IDLE
.
Pemutaran yang gagal atau dihentikan dapat dicoba lagi dengan memanggil ExoPlayer.prepare
.
Perlu diketahui bahwa beberapa implementasi Player
meneruskan instance subclass
PlaybackException
untuk memberikan informasi tambahan tentang kegagalan. Misalnya, ExoPlayer
meneruskan ExoPlaybackException
, yang memiliki type
,
rendererIndex
, dan kolom khusus ExoPlayer lainnya.
Contoh berikut menunjukkan cara mendeteksi kapan 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 pada objek
Player.Listener
yang terdaftar. Alasannya menunjukkan apakah ini adalah transisi
otomatis, pencarian (misalnya setelah memanggil player.next()
), pengulangan
item yang sama, atau disebabkan oleh perubahan playlist (misalnya, jika item yang
sedang diputar dihapus).
Metadata
Metadata yang ditampilkan dari player.getCurrentMediaMetadata()
dapat berubah karena berbagai
alasan: transisi playlist, pembaruan metadata in-stream, atau pembaruan
MediaItem
saat ini di tengah pemutaran.
Jika tertarik dengan perubahan metadata, misalnya untuk mengupdate UI yang menampilkan
judul saat ini, Anda dapat memproses onMediaMetadataChanged
.
Mencari
Memanggil metode Player.seekTo
akan menghasilkan serangkaian callback ke instance
Player.Listener
yang terdaftar:
onPositionDiscontinuity
denganreason=DISCONTINUITY_REASON_SEEK
. Ini adalah hasil langsung dari memanggilPlayer.seekTo
. Callback memiliki kolomPositionInfo
untuk posisi sebelum dan setelah pencarian.onPlaybackStateChanged
dengan perubahan status langsung yang terkait dengan pencarian. Perhatikan bahwa mungkin tidak ada perubahan seperti itu.
Callback individual versus onEvents
Pemroses dapat memilih antara menerapkan callback individual seperti onIsPlayingChanged(boolean isPlaying)
, dan callback onEvents(Player player, Events events)
generik. Callback generik memberikan
akses ke objek Player
dan menentukan kumpulan events
yang terjadi
bersama. Callback ini selalu dipanggil setelah callback yang terkait dengan
peristiwa individual.
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 sebaiknya dilakukan dalam kasus berikut:
- Pemroses tertarik dengan alasan perubahan. Misalnya, alasan yang diberikan untuk
onPlayWhenReadyChanged
atauonMediaItemTransition
. - Pemroses hanya bertindak pada nilai baru yang diberikan melalui parameter callback atau memicu hal lain yang tidak bergantung pada parameter callback.
- Implementasi pemroses lebih memilih indikasi yang jelas dan dapat dibaca terkait pemicu peristiwa dalam nama metode.
- Pemroses melaporkan ke sistem analisis yang perlu mengetahui setiap peristiwa dan perubahan status.
onEvents(Player player, Events events)
generik harus dipilih dalam
kasus berikut:
- Pemroses ingin memicu logika yang sama untuk beberapa peristiwa. Misalnya, mengupdate UI untuk
onPlaybackStateChanged
danonPlayWhenReadyChanged
. - Pemroses perlu mengakses objek
Player
untuk memicu peristiwa lebih lanjut, misalnya mencari setelah transisi item media. - Pemroses bermaksud menggunakan beberapa nilai status yang dilaporkan
melalui callback terpisah secara bersamaan, atau digabungkan dengan metode
pengambil
Player
. Misalnya, penggunaanPlayer.getCurrentWindowIndex()
denganTimeline
yang disediakan dionTimelineChanged
hanya aman dari dalam callbackonEvents
. - Pemroses tertarik apakah peristiwa secara logis terjadi bersamaan. Misalnya,
onPlaybackStateChanged
keSTATE_BUFFERING
karena transisi item media.
Pada beberapa kasus, pemroses mungkin perlu menggabungkan masing-masing callback dengan
callback onEvents
umum, misalnya untuk merekam alasan perubahan item media
dengan onMediaItemTransition
, tetapi hanya bertindak setelah semua perubahan status dapat digunakan
bersama di onEvents
.
Menggunakan AnalyticsListener
Saat menggunakan ExoPlayer
, AnalyticsListener
dapat didaftarkan dengan pemutar
dengan memanggil addAnalyticsListener
. Implementasi AnalyticsListener
dapat
memproses peristiwa mendetail yang mungkin berguna untuk tujuan analisis dan
logging. Lihat halaman analisis untuk detail selengkapnya.
Menggunakan EventLogger
EventLogger
adalah AnalyticsListener
yang disediakan langsung oleh library untuk
tujuan logging. Tambahkan EventLogger
ke ExoPlayer
untuk mengaktifkan logging tambahan
yang berguna dengan satu baris:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Lihat halaman logging debug untuk detail selengkapnya.
Peristiwa pengaktifan pada posisi pemutaran yang ditentukan
Beberapa kasus penggunaan memerlukan pengaktifan peristiwa pada posisi pemutaran yang ditentukan. Ini didukung menggunakan PlayerMessage
. PlayerMessage
dapat dibuat menggunakan
ExoPlayer.createMessage
. Posisi pemutaran yang harus dijalankan
dapat ditetapkan menggunakan PlayerMessage.setPosition
. Pesan dijalankan di
thread pemutaran secara default, tetapi dapat disesuaikan menggunakan
PlayerMessage.setLooper
. PlayerMessage.setDeleteAfterDelivery
dapat digunakan untuk mengontrol apakah pesan akan dieksekusi setiap kali posisi pemutaran yang ditentukan ditemukan (ini dapat terjadi beberapa kali karena mode pencarian dan pengulangan), atau hanya pertama kali. Setelah
dikonfigurasi, PlayerMessage
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();